summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/theme-tools/site-logo')
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css12
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css49
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php109
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php377
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php44
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php176
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js160
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js24
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js46
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js1
14 files changed, 1002 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css
new file mode 100644
index 00000000..d5441db1
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css
@@ -0,0 +1,12 @@
+/**
+ * RTL styles for the Site Logo control. Just swaps the button sides.
+ */
+#customize-control-site_logo .remove {
+ float: right;
+ margin-left: 3px;
+}
+
+#customize-control-site_logo .new,
+#customize-control-site_logo .change {
+ float: left;
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css
new file mode 100644
index 00000000..1893fe9c
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css
@@ -0,0 +1 @@
+#customize-control-site_logo .remove{float:right;margin-left:3px}#customize-control-site_logo .change,#customize-control-site_logo .new{float:left} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css
new file mode 100644
index 00000000..b9a10fe6
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css
@@ -0,0 +1,49 @@
+/**
+ * Styles for the Site Logo control.
+ */
+#customize-control-site_logo .current {
+ margin-bottom: 6px;
+}
+
+#customize-control-site_logo .current span {
+ border: 1px solid #eee;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+ color: #555;
+ display: block;
+ overflow: hidden;
+ line-height: 40px;
+ min-height: 40px;
+ padding: 0 6px;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+#customize-control-site_logo .current img {
+ max-width: 100%;
+}
+
+#customize-control-site_logo button.new,
+#customize-control-site_logo button.change,
+#customize-control-site_logo button.remove {
+ height: auto;
+ width: 48%;
+ white-space: normal;
+}
+
+#customize-control-site_logo .remove {
+ float: left;
+ margin-right: 3px;
+}
+
+#customize-control-site_logo .new,
+#customize-control-site_logo .change {
+ float: right;
+}
+
+#customize-control-site_logo .customize-control-description {
+ display: block;
+ clear: both;
+ margin-bottom: 10px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css
new file mode 100644
index 00000000..7fcee5ae
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css
@@ -0,0 +1 @@
+#customize-control-site_logo .current{margin-bottom:6px}#customize-control-site_logo .current span{border:1px solid #eee;-webkit-border-radius:2px;border-radius:2px;color:#555;display:block;overflow:hidden;line-height:40px;min-height:40px;padding:0 6px;text-align:center;text-overflow:ellipsis;white-space:nowrap}#customize-control-site_logo .current img{max-width:100%}#customize-control-site_logo button.change,#customize-control-site_logo button.new,#customize-control-site_logo button.remove{height:auto;width:48%;white-space:normal}#customize-control-site_logo .remove{float:left;margin-right:3px}#customize-control-site_logo .change,#customize-control-site_logo .new{float:right}#customize-control-site_logo .customize-control-description{display:block;clear:both;margin-bottom:10px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php
new file mode 100644
index 00000000..5e23507d
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * Custom logo uploader control for the Customizer.
+ *
+ * @package Jetpack
+ */
+class Site_Logo_Image_Control extends WP_Customize_Control {
+ /**
+ * Constructor for our custom control.
+ *
+ * @param object $wp_customize
+ * @param string $control_id
+ * @param array $args
+ * @uses Site_Logo_Image_Control::l10n()
+ */
+ public function __construct( $wp_customize, $control_id, $args = array() ) {
+ // declare these first so they can be overridden
+ $this->l10n = array(
+ 'upload' => __( 'Add logo', 'jetpack' ),
+ 'set' => __( 'Set as logo', 'jetpack' ),
+ 'choose' => __( 'Choose logo', 'jetpack' ),
+ 'change' => __( 'Change logo', 'jetpack' ),
+ 'remove' => __( 'Remove logo', 'jetpack' ),
+ 'placeholder' => __( 'No logo set', 'jetpack' ),
+ );
+
+ parent::__construct( $wp_customize, $control_id, $args );
+ }
+
+ /**
+ * This will be critical for our JS constructor.
+ */
+ public $type = 'site_logo';
+
+ /**
+ * Allows overriding of global labels by a specific control.
+ */
+ public $l10n = array();
+
+ /**
+ * The type of files that should be allowed by the media modal.
+ */
+ public $mime_type = 'image';
+
+ /**
+ * Enqueue our media manager resources, scripts, and styles.
+ *
+ * @uses wp_enqueue_media()
+ * @uses wp_enqueue_style()
+ * @uses wp_enqueue_script()
+ * @uses plugins_url()
+ */
+ public function enqueue() {
+ // Enqueues all needed media resources.
+ wp_enqueue_media();
+
+ // Enqueue our control script and styles.
+ wp_enqueue_style( 'site-logo-control', plugins_url( '../css/site-logo-control.css', __FILE__ ) );
+ wp_enqueue_script( 'site-logo-control', plugins_url( '../js/site-logo-control.js', __FILE__ ), array( 'media-views', 'customize-controls', 'underscore' ), '', true );
+ }
+
+ /**
+ * Check if we have an active site logo.
+ *
+ * @uses get_option()
+ * @return boolean
+ */
+ public function has_site_logo() {
+ $logo = get_option( 'site_logo' );
+
+ if ( empty( $logo['url'] ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Display our custom control in the Customizer.
+ *
+ * @uses Site_Logo_Image_Control::l10n()
+ * @uses Site_Logo_Image_Control::mime_type()
+ * @uses Site_Logo_Image_Control::label()
+ * @uses Site_Logo_Image_Control::description()
+ * @uses esc_attr()
+ * @uses esc_html()
+ */
+ public function render_content() {
+ // We do this to allow the upload control to specify certain labels
+ $l10n = json_encode( $this->l10n );
+
+ // Control title
+ printf(
+ '<span class="customize-control-title" data-l10n="%s" data-mime="%s">%s</span>',
+ esc_attr( $l10n ),
+ esc_attr( $this->mime_type ),
+ esc_html( $this->label )
+ );
+
+ // Control description
+ if ( ! empty( $this->description ) ) : ?>
+ <span class="description customize-control-description"><?php echo $this->description; ?></span>
+ <?php endif; ?>
+
+ <div class="current"></div>
+ <div class="actions"></div>
+ <?php
+ }
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php
new file mode 100644
index 00000000..75fe80b1
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php
@@ -0,0 +1,377 @@
+<?php
+/**
+ * Our Site Logo class for managing a theme-agnostic logo through the Customizer.
+ *
+ * @package Jetpack
+ */
+class Site_Logo {
+ /**
+ * Stores our single instance.
+ */
+ private static $instance;
+
+ /**
+ * Stores our current logo settings.
+ */
+ public $logo;
+
+ /**
+ * Return our instance, creating a new one if necessary.
+ *
+ * @uses Site_Logo::$instance
+ * @return object Site_Logo
+ */
+ public static function instance() {
+ if ( ! isset( self::$instance ) ) {
+ self::$instance = new Site_Logo();
+ self::$instance->register_hooks();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get our current logo settings stored in options.
+ *
+ * @uses get_option()
+ */
+ private function __construct() {
+ $this->logo = get_option( 'site_logo', null );
+ }
+
+ /**
+ * Register our actions and filters.
+ *
+ * @uses Site_Logo::head_text_styles()
+ * @uses Site_Logo::customize_register()
+ * @uses Site_Logo::preview_enqueue()
+ * @uses Site_Logo::body_classes()
+ * @uses Site_Logo::media_manager_image_sizes()
+ * @uses add_action
+ * @uses add_filter
+ */
+ public function register_hooks() {
+ // This would only happen if a theme supports BOTH site-logo and custom-logo for some reason
+ if ( current_theme_supports( 'custom-logo' ) ) {
+ return;
+ }
+
+ add_action( 'wp_head', array( $this, 'head_text_styles' ) );
+ add_action( 'customize_register', array( $this, 'customize_register' ) );
+ add_action( 'customize_preview_init', array( $this, 'preview_enqueue' ) );
+ add_action( 'delete_attachment', array( $this, 'reset_on_attachment_delete' ) );
+ add_filter( 'body_class', array( $this, 'body_classes' ) );
+ add_filter( 'image_size_names_choose', array( $this, 'media_manager_image_sizes' ) );
+ add_filter( 'display_media_states', array( $this, 'add_media_state' ) );
+ }
+
+ /**
+ * Add our logo uploader to the Customizer.
+ *
+ * @param object $wp_customize Customizer object.
+ * @uses current_theme_supports()
+ * @uses current_theme_supports()
+ * @uses WP_Customize_Manager::add_setting()
+ * @uses WP_Customize_Manager::add_control()
+ * @uses Site_Logo::sanitize_checkbox()
+ */
+ public function customize_register( $wp_customize ) {
+ // Include our custom control.
+ require dirname( __FILE__ ) . '/class-site-logo-control.php';
+
+ // Add a setting to hide header text if the theme isn't supporting the feature itself
+ if ( ! current_theme_supports( 'custom-header' ) ) {
+ $wp_customize->add_setting(
+ 'site_logo_header_text',
+ array(
+ 'default' => 1,
+ 'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
+ 'transport' => 'postMessage',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Control(
+ $wp_customize,
+ 'site_logo_header_text',
+ array(
+ 'label' => __( 'Display Header Text', 'jetpack' ),
+ 'section' => 'title_tagline',
+ 'settings' => 'site_logo_header_text',
+ 'type' => 'checkbox',
+ )
+ )
+ );
+ }
+
+ // Add the setting for our logo value.
+ $wp_customize->add_setting(
+ 'site_logo',
+ array(
+ 'capability' => 'manage_options',
+ 'default' => array(
+ 'id' => 0,
+ 'sizes' => array(),
+ 'url' => false,
+ ),
+ 'sanitize_callback' => array( $this, 'sanitize_logo_setting' ),
+ 'transport' => 'postMessage',
+ 'type' => 'option',
+ )
+ );
+
+ // Add our image uploader.
+ $wp_customize->add_control(
+ new Site_Logo_Image_Control(
+ $wp_customize,
+ 'site_logo',
+ array(
+ 'label' => __( 'Logo', 'jetpack' ),
+ 'section' => 'title_tagline',
+ 'settings' => 'site_logo',
+ )
+ )
+ );
+ }
+
+ /**
+ * Enqueue scripts for the Customizer live preview.
+ *
+ * @uses wp_enqueue_script()
+ * @uses plugins_url()
+ * @uses current_theme_supports()
+ * @uses Site_Logo::header_text_classes()
+ * @uses wp_localize_script()
+ */
+ public function preview_enqueue() {
+ wp_enqueue_script( 'site-logo-preview', plugins_url( '../js/site-logo.js', __FILE__ ), array( 'media-views' ), '', true );
+
+ // Don't bother passing in header text classes if the theme supports custom headers.
+ if ( ! current_theme_supports( 'custom-header' ) ) {
+ $classes = jetpack_sanitize_header_text_classes( $this->header_text_classes() );
+ wp_enqueue_script( 'site-logo-header-text', plugins_url( '../js/site-logo-header-text.js', __FILE__ ), array( 'media-views' ), '', true );
+ wp_localize_script( 'site-logo-header-text', 'site_logo_header_classes', $classes );
+ }
+ }
+
+ /**
+ * Get header text classes. If not defined in add_theme_support(), defaults from Underscores will be used.
+ *
+ * @uses get_theme_support
+ * @return string String of classes to hide
+ */
+ public function header_text_classes() {
+ $args = get_theme_support( 'site-logo' );
+
+ if ( isset( $args[0]['header-text'] ) ) {
+ // Use any classes defined in add_theme_support().
+ $classes = $args[0]['header-text'];
+ } else {
+ // Otherwise, use these defaults, which will work with any Underscores-based theme.
+ $classes = array(
+ 'site-title',
+ 'site-description',
+ );
+ }
+
+ // If we've got an array, reduce them to a string for output
+ if ( is_array( $classes ) ) {
+ $classes = (string) '.' . implode( ', .', $classes );
+ } else {
+ $classes = (string) '.' . $classes;
+ }
+
+ return $classes;
+ }
+
+ /**
+ * Hide header text on front-end if necessary.
+ *
+ * @uses current_theme_supports()
+ * @uses get_theme_mod()
+ * @uses Site_Logo::header_text_classes()
+ * @uses esc_html()
+ */
+ public function head_text_styles() {
+ // Bail if our theme supports custom headers.
+ if ( current_theme_supports( 'custom-header' ) ) {
+ return;
+ }
+
+ // Is Display Header Text unchecked? If so, we need to hide our header text.
+ if ( ! get_theme_mod( 'site_logo_header_text', 1 ) ) {
+ $classes = $this->header_text_classes();
+ ?>
+ <!-- Site Logo: hide header text -->
+ <style type="text/css">
+ <?php echo jetpack_sanitize_header_text_classes( $classes ); ?> {
+ position: absolute;
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ </style>
+ <?php
+ }
+ }
+
+ /**
+ * Determine image size to use for the logo.
+ *
+ * @uses get_theme_support()
+ * @return string Size specified in add_theme_support declaration, or 'thumbnail' default
+ */
+ public function theme_size() {
+ $args = get_theme_support( 'site-logo' );
+ $valid_sizes = get_intermediate_image_sizes();
+
+ // Add 'full' to the list of accepted values.
+ $valid_sizes[] = 'full';
+
+ // If the size declared in add_theme_support is valid, use it; otherwise, just go with 'thumbnail'.
+ $size = ( isset( $args[0]['size'] ) && in_array( $args[0]['size'], $valid_sizes ) ) ? $args[0]['size'] : 'thumbnail';
+
+ return $size;
+ }
+
+ /**
+ * Make custom image sizes available to the media manager.
+ *
+ * @param array $sizes
+ * @uses get_intermediate_image_sizes()
+ * @return array All default and registered custom image sizes.
+ */
+ public function media_manager_image_sizes( $sizes ) {
+ // Get an array of all registered image sizes.
+ $intermediate = get_intermediate_image_sizes();
+
+ // Have we got anything fun to work with?
+ if ( is_array( $intermediate ) && ! empty( $intermediate ) ) {
+ foreach ( $intermediate as $key => $size ) {
+ // If the size isn't already in the $sizes array, add it.
+ if ( ! array_key_exists( $size, $sizes ) ) {
+ $sizes[ $size ] = $size;
+ }
+ }
+ }
+
+ return $sizes;
+ }
+
+ /**
+ * Add site logos to media states in the Media Manager.
+ *
+ * @return array The current attachment's media states.
+ */
+ public function add_media_state( $media_states ) {
+ // Only bother testing if we have a site logo set.
+ if ( $this->has_site_logo() ) {
+ global $post;
+
+ // If our attachment ID and the site logo ID match, this image is the site logo.
+ if ( $post->ID == $this->logo['id'] ) {
+ $media_states[] = __( 'Site Logo', 'jetpack' );
+ }
+ }
+
+ return $media_states;
+ }
+
+ /**
+ * Reset the site logo if the current logo is deleted in the media manager.
+ *
+ * @param int $site_id
+ * @uses Site_Logo::remove_site_logo()
+ */
+ public function reset_on_attachment_delete( $post_id ) {
+ if ( $this->logo['id'] == $post_id ) {
+ $this->remove_site_logo();
+ }
+ }
+
+ /**
+ * Determine if a site logo is assigned or not.
+ *
+ * @uses Site_Logo::$logo
+ * @return boolean True if there is an active logo, false otherwise
+ */
+ public function has_site_logo() {
+ return ( isset( $this->logo['id'] ) && 0 !== $this->logo['id'] ) ? true : false;
+ }
+
+ /**
+ * Reset the site logo option to zero (empty).
+ *
+ * @uses update_option()
+ */
+ public function remove_site_logo() {
+ update_option(
+ 'site_logo',
+ array(
+ 'id' => (int) 0,
+ 'sizes' => array(),
+ 'url' => '',
+ )
+ );
+ }
+
+ /**
+ * Adds custom classes to the array of body classes.
+ *
+ * @uses Site_Logo::has_site_logo()
+ * @return array Array of <body> classes
+ */
+ public function body_classes( $classes ) {
+ // Add a class if a Site Logo is active
+ if ( $this->has_site_logo() ) {
+ $classes[] = 'has-site-logo';
+ }
+
+ return $classes;
+ }
+
+ /**
+ * Sanitize our header text Customizer setting.
+ *
+ * @param $input
+ * @return mixed 1 if checked, empty string if not checked.
+ */
+ public function sanitize_checkbox( $input ) {
+ return ( 1 == $input ) ? 1 : '';
+ }
+
+ /**
+ * Validate and sanitize a new site logo setting.
+ *
+ * @param $input
+ * @return mixed 1 if checked, empty string if not checked.
+ */
+ public function sanitize_logo_setting( $input ) {
+ $input['id'] = absint( $input['id'] );
+ $input['url'] = esc_url_raw( $input['url'] );
+
+ // If the new setting doesn't point to a valid attachment, just reset the whole thing.
+ if ( false == wp_get_attachment_image_src( $input['id'] ) ) {
+ $input = array(
+ 'id' => (int) 0,
+ 'sizes' => array(),
+ 'url' => '',
+ );
+ }
+
+ return $input;
+ }
+}
+
+/**
+ * Allow themes and plugins to access Site_Logo methods and properties.
+ *
+ * @uses Site_Logo::instance()
+ * @return object Site_Logo
+ */
+function site_logo() {
+ return Site_Logo::instance();
+}
+
+/**
+ * One site logo, please.
+ */
+site_logo();
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php
new file mode 100644
index 00000000..d1098536
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Functions for maintaining backwards compatibility with unprefixed template tags from the original Site Logo plugin.
+ * These should never be used in themes; instead, use the template tags in functions.php.
+ * See: https://github.com/Automattic/jetpack/pull/956
+ *
+ * @package Jetpack
+ */
+
+if ( ! function_exists( 'the_site_logo' ) ) :
+ /**
+ * Unprefixed, backwards-compatible function for outputting the site logo.
+ *
+ * @uses jetpack_the_site_logo()
+ */
+ function the_site_logo() {
+ jetpack_the_site_logo();
+ }
+endif;
+
+if ( ! function_exists( 'has_site_logo' ) ) :
+ /**
+ * Unprefixed, backwards-compatible function for determining if a site logo has been set.
+ *
+ * @uses jetpack_has_site_logo()
+ * @return bool True if a site logo is set, false otherwise.
+ */
+ function has_site_logo() {
+ return jetpack_has_site_logo();
+ }
+endif;
+
+if ( ! function_exists( 'get_site_logo' ) ) :
+ /**
+ * Unprefixed, backwards-compatible function for getting either the site logo's image URL or its ID.
+ *
+ * @param string $show Return the site logo URL or ID.
+ * @uses jetpack_get_site_logo()
+ * @return string Site logo ID or URL (the default).
+ */
+ function get_site_logo( $show = 'url' ) {
+ return jetpack_get_site_logo( $show );
+ }
+endif;
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php
new file mode 100644
index 00000000..3b27b32f
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Functions and template tags for using site logos.
+ *
+ * @package Jetpack
+ */
+
+/**
+ * Retrieve the site logo URL or ID (URL by default). Pass in the string 'id' for ID.
+ *
+ * @uses get_option()
+ * @uses esc_url_raw()
+ * @uses set_url_scheme()
+ * @return mixed The URL or ID of our site logo, false if not set
+ * @since 1.0
+ */
+function jetpack_get_site_logo( $show = 'url' ) {
+ $logo = site_logo()->logo;
+
+ // Return false if no logo is set
+ if ( ! isset( $logo['id'] ) || 0 == $logo['id'] ) {
+ return false;
+ }
+
+ // Return the ID if specified, otherwise return the URL by default
+ if ( 'id' == $show ) {
+ return $logo['id'];
+ } else {
+ return esc_url_raw( set_url_scheme( $logo['url'] ) );
+ }
+}
+
+/**
+ * Retrieve an array of the dimensions of the Site Logo.
+ *
+ * @uses Site_Logo::theme_size()
+ * @uses get_option( 'thumbnail_size_w' )
+ * @uses get_option( 'thumbnail_size_h' )
+ * @uses global $_wp_additional_image_sizes;
+ *
+ * @since 3.6.0
+ *
+ * @return array $dimensions {
+ * An array of dimensions of the Site Logo.
+ *
+ * @type string $width Width of the logo in pixels.
+ * @type string $height Height of the logo in pixels.
+ * }
+ */
+function jetpack_get_site_logo_dimensions() {
+ // Get the image size to use with the logo.
+ $size = site_logo()->theme_size();
+
+ // If the size is the default `thumbnail`, get its dimensions. Otherwise, get them from $_wp_additional_image_sizes
+ if ( empty( $size ) ) {
+ return false;
+ } elseif ( 'thumbnail' == $size ) {
+ $dimensions = array(
+ 'width' => get_option( 'thumbnail_size_w' ),
+ 'height' => get_option( 'thumbnail_size_h' ),
+ );
+ } else {
+ global $_wp_additional_image_sizes;
+
+ if ( ! isset( $_wp_additional_image_sizes[ $size ] ) ) {
+ return false;
+ }
+
+ $dimensions = array(
+ 'width' => $_wp_additional_image_sizes[ $size ]['width'],
+ 'height' => $_wp_additional_image_sizes[ $size ]['height'],
+ );
+ }
+
+ return $dimensions;
+}
+
+/**
+ * Determine if a site logo is assigned or not.
+ *
+ * @uses get_option
+ * @return boolean True if there is an active logo, false otherwise
+ */
+function jetpack_has_site_logo() {
+ return site_logo()->has_site_logo();
+}
+
+/**
+ * Output an <img> tag of the site logo, at the size specified
+ * in the theme's add_theme_support() declaration.
+ *
+ * @uses Site_Logo::logo
+ * @uses Site_Logo::theme_size()
+ * @uses jetpack_has_site_logo()
+ * @uses jetpack_is_customize_preview()
+ * @uses esc_url()
+ * @uses home_url()
+ * @uses esc_attr()
+ * @uses wp_get_attachment_image()
+ * @uses apply_filters()
+ * @since 1.0
+ */
+function jetpack_the_site_logo() {
+ $logo = site_logo()->logo;
+ $logo_id = get_theme_mod( 'custom_logo' ); // Check for WP 4.5 Site Logo
+ $logo_id = $logo_id ? $logo_id : $logo['id']; // Use WP Core logo if present, otherwise use Jetpack's.
+ $size = site_logo()->theme_size();
+ $html = '';
+
+ // If no logo is set, but we're in the Customizer, leave a placeholder (needed for the live preview).
+ if ( ! jetpack_has_site_logo() ) {
+ if ( jetpack_is_customize_preview() ) {
+ $html = sprintf(
+ '<a href="%1$s" class="site-logo-link" style="display:none;"><img class="site-logo" data-size="%2$s" /></a>',
+ esc_url( home_url( '/' ) ),
+ esc_attr( $size )
+ );
+ }
+ }
+
+ // We have a logo. Logo is go.
+ else {
+ $html = sprintf(
+ '<a href="%1$s" class="site-logo-link" rel="home" itemprop="url">%2$s</a>',
+ esc_url( home_url( '/' ) ),
+ wp_get_attachment_image(
+ $logo_id,
+ $size,
+ false,
+ array(
+ 'class' => "site-logo attachment-$size",
+ 'data-size' => $size,
+ 'itemprop' => 'logo',
+ )
+ )
+ );
+ }
+
+ /**
+ * Filter the Site Logo output.
+ *
+ * @module theme-tools
+ *
+ * @since 3.2.0
+ *
+ * @param string $html Site Logo HTML output.
+ * @param array $logo Array of Site Logo details.
+ * @param string $size Size specified in add_theme_support declaration, or 'thumbnail' default.
+ */
+ echo apply_filters( 'jetpack_the_site_logo', $html, $logo, $size );
+}
+
+/**
+ * Whether the site is being previewed in the Customizer.
+ * Duplicate of core function until 4.0 is released.
+ *
+ * @global WP_Customize_Manager $wp_customize Customizer instance.
+ * @return bool True if the site is being previewed in the Customizer, false otherwise.
+ */
+function jetpack_is_customize_preview() {
+ global $wp_customize;
+
+ return is_a( $wp_customize, 'WP_Customize_Manager' ) && $wp_customize->is_preview();
+}
+
+/**
+ * Sanitize the string of classes used for header text.
+ * Limit to A-Z,a-z,0-9,(space),(comma),_,-
+ *
+ * @return string Sanitized string of CSS classes.
+ */
+function jetpack_sanitize_header_text_classes( $classes ) {
+ $classes = preg_replace( '/[^A-Za-z0-9\,\ ._-]/', '', $classes );
+
+ return $classes;
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js
new file mode 100644
index 00000000..c4cce6c2
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js
@@ -0,0 +1,160 @@
+/**
+ * JS for handling the Site Logo Customizer control.
+ */
+( function( wp, $ ) {
+ // nice shortcut
+ var api = wp.customize;
+ /**
+ * The Customizer looks for wp.customizer.controlConstructor[type] functions
+ * where type == the type member of a WP_Customize_Control
+ */
+ api.controlConstructor.site_logo = api.Control.extend( {
+ /**
+ * This method is called when the control is ready to run.
+ * Do all of your setup and event binding here.
+ */
+ ready: function() {
+ // this.container is a jQuery object of your container
+
+ // grab the bits of data from the title for specifying this control
+ var data = this.container.find( '.customize-control-title' ).data();
+
+ // Use specific l10n data for this control where available
+ this.l10n = data.l10n;
+ // Grab mime type
+ this.mime = data.mime;
+
+ // Set up image container and button elements. Cache for re-use.
+ this.$imgContainer = $( '#customize-control-site_logo .current' );
+ this.$btnContainer = $( '#customize-control-site_logo .actions' );
+ this.$img = $( '<img class="site-logo-thumbnail" />' ).prependTo( this.$imgContainer );
+ this.$placeholder = $( '<span>' + this.l10n.placeholder + '</span>' ).prependTo(
+ this.$imgContainer
+ );
+ this.$btnAdd = $(
+ '<button type="button" class="button new">' + this.l10n.upload + '</button>'
+ ).prependTo( this.$btnContainer );
+ this.$btnChange = $(
+ '<button type="button" class="button change">' + this.l10n.change + '</button>'
+ ).prependTo( this.$btnContainer );
+ this.$btnRemove = $(
+ '<button type="button" class="button remove">' + this.l10n.remove + '</button>'
+ ).prependTo( this.$btnContainer );
+
+ // handy shortcut so we don't have to us _.bind every time we add a callback
+ _.bindAll( this, 'removeImg', 'upload', 'render', 'pick' );
+
+ this.$btnAdd.on( 'click', this.upload );
+ this.$btnChange.on( 'click', this.upload );
+ this.$btnRemove.on( 'click', this.removeImg );
+
+ // Call render method whenever setting is changed.
+ this.setting.bind( 'change', this.render );
+ // Do initial rendering.
+ this.render();
+ },
+ /**
+ * Remember that _.bind was used to maintain `this` as the control
+ * object rather than the usual jQuery way of binding to the DOM element.
+ */
+ upload: function( event ) {
+ event.preventDefault();
+
+ if ( ! this.frame ) {
+ this.initFrame();
+ }
+
+ this.frame.open();
+ },
+ /**
+ * Set the media frame so that it can be reused and accessed when needed.
+ */
+ initFrame: function() {
+ this.frame = wp.media( {
+ // The title of the media modal
+ title: this.l10n.choose,
+ // restrict to specified mime type
+ library: {
+ type: this.mime,
+ },
+ // Customize the submit button.
+ button: {
+ // Set the text of the button.
+ text: this.l10n.set,
+ },
+ // Just one, thanks.
+ multiple: false,
+ } );
+
+ // When an image is selected, run a callback.
+ this.frame.on( 'select', this.pick );
+ },
+ /**
+ * Fired when an image is selected in the media modal. Gets the selected
+ * image information, and sets it within the control.
+ */
+ pick: function() {
+ // get the attachment from the modal frame
+ var attachment = this.frame
+ .state()
+ .get( 'selection' )
+ .single();
+ if ( 'image' === attachment.get( 'type' ) ) {
+ // set the setting - the callback will take care of rendering
+ this.setting( this.reduceMembers( attachment.toJSON() ) );
+ }
+ },
+ /**
+ * Reduces the attachment object to just the few desired members.
+ * @param {object} attachment An attachment object provided by the
+ * medial modal.
+ * @return {object} A reduced media object.
+ */
+ reduceMembers: function( attachment ) {
+ var desired = [ 'id', 'sizes', 'url' ],
+ output = {};
+ $.each( desired, function( i, key ) {
+ output[ key ] = attachment[ key ];
+ } );
+ return output;
+ },
+ /**
+ * Called on init and whenever a setting is changed. Shows the thumbnail
+ * when there is one or the upload button when there isn't.
+ */
+ render: function() {
+ var value = this.setting();
+
+ if ( value && value.url ) {
+ this.$placeholder.hide();
+ if ( ! value.sizes || ! value.sizes.medium ) {
+ this.$img.attr( 'src', value.url );
+ } else {
+ this.$img.attr( 'src', value.sizes.medium.url );
+ }
+ this.$img.show();
+ this.$btnRemove.show();
+ this.$btnChange.show();
+ this.$btnAdd.hide();
+ } else {
+ this.$img.hide();
+ this.$placeholder.show();
+ this.$btnRemove.hide();
+ this.$btnChange.hide();
+ this.$btnAdd.show();
+ }
+ },
+ /**
+ * Called when the "Remove Image" link is clicked. Sets thes setting back
+ * to its default state.
+ * @param {object} event jQuery Event object from click event
+ */
+ removeImg: function( event ) {
+ event.preventDefault();
+ this.setting( {
+ url: '',
+ id: 0,
+ } );
+ },
+ } );
+} )( this.wp, jQuery );
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js
new file mode 100644
index 00000000..171d98e8
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js
@@ -0,0 +1 @@
+(function(a,c){var b=a.customize;b.controlConstructor.site_logo=b.Control.extend({ready:function(){var d=this.container.find(".customize-control-title").data();this.l10n=d.l10n;this.mime=d.mime;this.$imgContainer=c("#customize-control-site_logo .current");this.$btnContainer=c("#customize-control-site_logo .actions");this.$img=c('<img class="site-logo-thumbnail" />').prependTo(this.$imgContainer);this.$placeholder=c("<span>"+this.l10n.placeholder+"</span>").prependTo(this.$imgContainer);this.$btnAdd=c('<button type="button" class="button new">'+this.l10n.upload+"</button>").prependTo(this.$btnContainer);this.$btnChange=c('<button type="button" class="button change">'+this.l10n.change+"</button>").prependTo(this.$btnContainer);this.$btnRemove=c('<button type="button" class="button remove">'+this.l10n.remove+"</button>").prependTo(this.$btnContainer);_.bindAll(this,"removeImg","upload","render","pick");this.$btnAdd.on("click",this.upload);this.$btnChange.on("click",this.upload);this.$btnRemove.on("click",this.removeImg);this.setting.bind("change",this.render);this.render()},upload:function(d){d.preventDefault();if(!this.frame){this.initFrame()}this.frame.open()},initFrame:function(){this.frame=a.media({title:this.l10n.choose,library:{type:this.mime},button:{text:this.l10n.set},multiple:false});this.frame.on("select",this.pick)},pick:function(){var d=this.frame.state().get("selection").first().toJSON();d=this.reduceMembers(d);this.setting(d)},reduceMembers:function(f){var e=["id","sizes","url"],d={};c.each(e,function(h,g){d[g]=f[g]});return d},render:function(){var d=this.setting();if(d&&d.url){this.$placeholder.hide();if(!d.sizes||!d.sizes.medium){this.$img.attr("src",d.url)}else{this.$img.attr("src",d.sizes.medium.url)}this.$img.show();this.$btnRemove.show();this.$btnChange.show();this.$btnAdd.hide()}else{this.$img.hide();this.$placeholder.show();this.$btnRemove.hide();this.$btnChange.hide();this.$btnAdd.show()}},removeImg:function(d){d.preventDefault();this.setting({url:"",id:0})}})})(this.wp,jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js
new file mode 100644
index 00000000..82673a7e
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js
@@ -0,0 +1,24 @@
+/* global site_logo_header_classes */
+/**
+ * JS for handling the "Display Header Text" setting's realtime preview.
+ */
+( function( $ ) {
+ var api = wp.customize,
+ $classes = site_logo_header_classes;
+
+ api( 'site_logo_header_text', function( value ) {
+ value.bind( function( to ) {
+ if ( true === to ) {
+ $( $classes ).css( {
+ position: 'static',
+ clip: 'auto',
+ } );
+ } else {
+ $( $classes ).css( {
+ position: 'absolute',
+ clip: 'rect(1px 1px 1px 1px)',
+ } );
+ }
+ } );
+ } );
+} )( jQuery );
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js
new file mode 100644
index 00000000..39c56ec0
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js
@@ -0,0 +1 @@
+!function(t){var i=wp.customize,o=site_logo_header_classes;i("site_logo_header_text",function(i){i.bind(function(i){t(o).css(!0===i?{position:"static",clip:"auto"}:{position:"absolute",clip:"rect(1px 1px 1px 1px)"})})})}(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js
new file mode 100644
index 00000000..6c959c0c
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js
@@ -0,0 +1,46 @@
+/**
+ * JS for handling the Site Logo real-time display in the Customizer preview frame.
+ */
+( function( $ ) {
+ var api = wp.customize,
+ $body,
+ $anchor,
+ $logo,
+ size;
+
+ function cacheSelectors() {
+ $body = $( 'body' );
+ $anchor = $( '.site-logo-link' );
+ $logo = $( '.site-logo' );
+ size = $logo.attr( 'data-size' );
+ }
+
+ api( 'site_logo', function( value ) {
+ value.bind( function( newVal ) {
+ // grab selectors the first time through
+ if ( ! $body ) {
+ cacheSelectors();
+ }
+
+ // Let's update our preview logo.
+ if ( newVal && newVal.url ) {
+ // If the source was smaller than the size required by the theme, give the biggest we've got.
+ if ( ! newVal.sizes[ size ] ) {
+ size = 'full';
+ }
+
+ $logo.attr( {
+ height: newVal.sizes[ size ].height,
+ width: newVal.sizes[ size ].width,
+ src: newVal.sizes[ size ].url,
+ } );
+
+ $anchor.show();
+ $body.addClass( 'has-site-logo' );
+ } else {
+ $anchor.hide();
+ $body.removeClass( 'has-site-logo' );
+ }
+ } );
+ } );
+} )( jQuery );
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js
new file mode 100644
index 00000000..a6fe41eb
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js
@@ -0,0 +1 @@
+(function(d){var e=wp.customize,c,f,g,a;e("site_logo",function(e){e.bind(function(b){c||(c=d("body"),f=d(".site-logo-link"),g=d(".site-logo"),a=g.attr("data-size"));b&&b.url?(b.sizes[a]||(a="full"),g.attr({height:b.sizes[a].height,width:b.sizes[a].width,src:b.sizes[a].url}),f.show(),c.addClass("has-site-logo")):(f.hide(),c.removeClass("has-site-logo"))})})})(jQuery); \ No newline at end of file