Make WordPress Core

Ticket #33755: 33755.10.diff

File 33755.10.diff, 24.7 KB (added by adamsilverstein, 9 years ago)
  • src/wp-admin/css/customize-controls.css

    diff --git src/wp-admin/css/customize-controls.css src/wp-admin/css/customize-controls.css
    index 4b153a4..585878b 100644
    p.customize-section-description { 
    725725.customize-control-background .current,
    726726.customize-control-cropped_image .current,
    727727.customize-control-site_icon .current,
     728.customize-control-site_logo .current,
    728729.customize-control-header .current {
    729730        margin-bottom: 8px;
    730731}
    p.customize-section-description { 
    766767.customize-control-site_icon .remove-button,
    767768.customize-control-site_icon .default-button,
    768769.customize-control-site_icon .upload-button,
     770.customize-control-site_logo .remove-button,
     771.customize-control-site_logo .default-button,
     772.customize-control-site_logo .upload-button,
    769773.customize-control-header button.new,
    770774.customize-control-header button.remove {
    771775        white-space: normal;
    p.customize-section-description { 
    779783.customize-control-background .current .container,
    780784.customize-control-cropped_image .current .container,
    781785.customize-control-site_icon .current .container,
     786.customize-control-site_logo .current .container,
    782787.customize-control-header .current .container {
    783788        overflow: hidden;
    784789        -webkit-border-radius: 2px;
    p.customize-section-description { 
    792797.customize-control-background .current .container,
    793798.customize-control-cropped_image .current .container,
    794799.customize-control-site_icon .current .container,
     800.customize-control-site_logo .current .container,
    795801.customize-control-image .current .container {
    796802        min-height: 40px;
    797803}
    p.customize-section-description { 
    802808.customize-control-background .placeholder,
    803809.customize-control-cropped_image .placeholder,
    804810.customize-control-site_icon .placeholder,
     811.customize-control-site_logo .placeholder,
    805812.customize-control-header .placeholder {
    806813        width: 100%;
    807814        position: relative;
    p.customize-section-description { 
    815822.customize-control-background .inner,
    816823.customize-control-cropped_image .inner,
    817824.customize-control-site_icon .inner,
     825.customize-control-site_logo .inner,
    818826.customize-control-header .inner {
    819827        display: none;
    820828        position: absolute;
    p.customize-section-description { 
    830838.customize-control-background .inner,
    831839.customize-control-cropped_image .inner,
    832840.customize-control-site_icon .inner,
     841.customize-control-site_logo .inner,
    833842.customize-control-image .inner {
    834843        display: block;
    835844        min-height: 40px;
    p.customize-section-description { 
    841850.customize-control-background .inner,
    842851.customize-control-cropped_image .inner,
    843852.customize-control-site_icon .inner,
     853.customize-control-site_logo.inner,
    844854.customize-control-header .inner,
    845855.customize-control-header .inner .dashicons {
    846856        line-height: 20px;
    p.customize-section-description { 
    984995.customize-control-cropped_image .default-button,
    985996.customize-control-site_icon .remove-button,
    986997.customize-control-site_icon .default-button,
     998.customize-control-site_logo .remove-button,
     999.customize-control-site_logo .default-button,
    9871000.customize-control-header .remove {
    9881001        float: left;
    9891002        margin-right: 3px;
    p.customize-section-description { 
    9951008.customize-control-background .upload-button,
    9961009.customize-control-cropped_image .upload-button,
    9971010.customize-control-site_icon .upload-button,
     1011.customize-control-site_logo .upload-button,
    9981012.customize-control-header .new {
    9991013        float: right;
    10001014}
  • src/wp-admin/includes/admin.php

    diff --git src/wp-admin/includes/admin.php src/wp-admin/includes/admin.php
    index a44abba..5b749f9 100644
    require_once(ABSPATH . 'wp-admin/includes/user.php'); 
    7272/** WordPress Site Icon API */
    7373require_once(ABSPATH . 'wp-admin/includes/class-wp-site-icon.php');
    7474
     75/** WordPress Site Logo API */
     76require_once(ABSPATH . 'wp-admin/includes/class-wp-site-logo.php');
     77
    7578/** WordPress Update Administration API */
    7679require_once(ABSPATH . 'wp-admin/includes/update.php');
    7780
  • src/wp-admin/includes/class-wp-site-icon.php

    diff --git src/wp-admin/includes/class-wp-site-icon.php src/wp-admin/includes/class-wp-site-icon.php
    index 8c06db6..104d99c 100644
    class WP_Site_Icon { 
    6464
    6565                // Our regular Favicon.
    6666                32,
     67
    6768        );
    6869
    6970        /**
  • new file src/wp-admin/includes/class-wp-site-logo.php

    diff --git src/wp-admin/includes/class-wp-site-logo.php src/wp-admin/includes/class-wp-site-logo.php
    new file mode 100644
    index 0000000..4950393
    - +  
     1<?php
     2/**
     3 * Administration API: WP_Site_Logo class
     4 *
     5 * @package WordPress
     6 * @subpackage Administration
     7 * @since 4.5.0
     8 */
     9
     10/**
     11 * Core class used to implement site logo functionality.
     12 *
     13 * @since 4.5.0
     14 */
     15class WP_Site_Logo {
     16
     17        /**
     18         * Get current logo settings stored in options.
     19         *
     20         * @since 4.5.0
     21         * @access public
     22         */
     23        public function __construct() {
     24                add_action( 'wp_head', array( $this, 'head_text_styles' ) );
     25                add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ) );
     26                add_filter( 'image_size_names_choose', array( $this, 'media_manager_image_sizes' ) );
     27        }
     28
     29        /**
     30         * Enqueue scripts for the Customizer live preview.
     31         *
     32         * @since 4.5.0
     33         * @access public
     34         */
     35        public function preview_enqueue() {
     36
     37                // Don't bother passing in header text classes if the theme supports custom headers.
     38                if ( ! current_theme_supports( 'custom-header' ) ) {
     39                        wp_enqueue_script( 'site-logo-header-text', plugins_url( '../js/site-logo-header-text.js', __FILE__ ), array( 'media-views' ), '', true );
     40                        wp_localize_script( 'site-logo-header-text', 'site_logo_header_classes', $this->header_text_classes() );
     41                }
     42        }
     43
     44        /**
     45         * Get header text classes. If not defined in add_theme_support(), defaults from Underscores will be used.
     46         *
     47         * @since 4.5.0
     48         * @access public
     49         *
     50         * @return string String of classes to hide
     51         */
     52        public function header_text_classes() {
     53                $args = get_theme_support( 'site-logo' );
     54
     55                if ( isset( $args[0]['header-text'] ) ) {
     56                        // Use any classes defined in add_theme_support().
     57                        $classes = $args[0]['header-text'];
     58                } else {
     59                        // Otherwise, use these defaults, which will work with any Underscores-based theme.
     60                        $classes = array(
     61                                'site-title',
     62                                'site-description',
     63                        );
     64                }
     65
     66                // If we've got an array, reduce them to a string for output.
     67                if ( is_array( $classes ) ) {
     68                        $classes = array_map( 'sanitize_html_class', $classes );
     69                        $classes = (string) '.' . implode( ', .', $classes );
     70                } else {
     71                        $classes = (string) '.' . $classes;
     72                }
     73
     74                return $classes;
     75        }
     76
     77        /**
     78         * Hide header text on front-end if necessary.
     79         *
     80         * @since 4.5.0
     81         * @access public
     82         */
     83        public function head_text_styles() {
     84                // Bail if our theme supports custom headers.
     85                if ( current_theme_supports( 'custom-header' ) || get_theme_mod( 'site_logo_header_text', true ) ) {
     86                        return;
     87                }
     88
     89                // Is Display Header Text unchecked? If so, we need to hide our header text.
     90                ?>
     91                <!-- Site Logo: hide header text -->
     92                <style type="text/css">
     93                        <?php echo sanitize_html_class( $this->header_text_classes() ); ?>  {
     94                                position: absolute;
     95                                clip: rect(1px, 1px, 1px, 1px);
     96                        }
     97                </style>
     98        <?php
     99        }
     100
     101        /**
     102         * Make custom image sizes available to the media manager.
     103         *
     104         * @since 4.5.0
     105         * @access public
     106         *
     107         * @param array $sizes Image sizes.
     108         * @return array All default and registered custom image sizes.
     109         */
     110        public function media_manager_image_sizes( $sizes ) {
     111                // Get an array of all registered image sizes.
     112                $intermediate = get_intermediate_image_sizes();
     113
     114                // Have we got anything fun to work with?
     115                if ( is_array( $intermediate ) && ! empty( $intermediate ) ) {
     116                        foreach ( $intermediate as $key => $size ) {
     117                                // If the size isn't already in the $sizes array, add it.
     118                                if ( ! array_key_exists( $size, $sizes ) ) {
     119                                        $sizes[ $size ] = $size;
     120                                }
     121                        }
     122                }
     123
     124                return $sizes;
     125        }
     126
     127        /**
     128         * Reset the site logo if the current logo is deleted in the media manager.
     129         *
     130         * @since 4.5.0
     131         * @access public
     132         *
     133         * @param int $post_id
     134         */
     135        public function delete_attachment_data( $post_id ) {
     136                $site_logo_id = get_option( 'site_logo' );
     137
     138                if ( $site_logo_id && $site_logo_id == $post_id ) {
     139                        delete_option( 'site_logo' );
     140                }
     141        }
     142
     143        /**
     144         * Sanitize our header text Customizer setting.
     145         *
     146         * @since 4.5.0
     147         * @access public
     148         *
     149         * @param int|string $input Input value.
     150         * @return int|string 1 if checked, empty string if not checked.
     151         */
     152        public function sanitize_checkbox( $input ) {
     153                return ( 1 == $input ) ? 1 : '';
     154        }
     155}
     156
     157/**
     158 * WP_Site_Logo instance.
     159 *
     160 * @global WP_Site_Logo $wp_site_logo
     161 */
     162$GLOBALS['wp_site_logo'] = new WP_Site_Logo;
  • src/wp-admin/includes/template.php

    diff --git src/wp-admin/includes/template.php src/wp-admin/includes/template.php
    index c658c6a..74d06ad 100644
    function _media_states( $post ) { 
    17481748                $media_states[] = __( 'Site Icon' );
    17491749        }
    17501750
     1751        if ( $post->ID == get_option( 'site_logo' ) ) {
     1752                $media_states[] = __( 'Logo' );
     1753        }
     1754
    17511755        /**
    17521756         * Filter the default media display states for items in the Media list table.
    17531757         *
    17541758         * @since 3.2.0
    17551759         *
    17561760         * @param array $media_states An array of media states. Default 'Header Image',
    1757          *                            'Background Image', 'Site Icon'.
     1761         *                            'Background Image', 'Site Icon', 'Logo'.
    17581762         */
    17591763        $media_states = apply_filters( 'display_media_states', $media_states );
    17601764
  • src/wp-admin/js/customize-controls.js

    diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js
    index 270770d..539b9bc 100644
     
    22962296        });
    22972297
    22982298        /**
     2299         * A control for selecting Site Logos.
     2300         *
     2301         * @class
     2302         * @augments wp.customize.MediaControl
     2303         * @augments wp.customize.Control
     2304         * @augments wp.customize.Class
     2305         */
     2306        api.SiteLogoControl = api.MediaControl.extend({
     2307
     2308                /**
     2309                 * When the control's DOM structure is ready,
     2310                 * set up internal event bindings.
     2311                 */
     2312                ready: function() {
     2313                        var control = this;
     2314
     2315                        // Shortcut so that we don't have to use _.bind every time we add a callback.
     2316                        _.bindAll( control, 'restoreDefault', 'removeFile', 'openFrame', 'select' );
     2317
     2318                        // Bind events, with delegation to facilitate re-rendering.
     2319                        control.container.on( 'click keydown', '.upload-button', control.openFrame );
     2320                        control.container.on( 'click keydown', '.thumbnail-image img', control.openFrame );
     2321                        control.container.on( 'click keydown', '.default-button', control.restoreDefault );
     2322                        control.container.on( 'click keydown', '.remove-button', control.removeFile );
     2323
     2324                        control.setting.bind( function( attachmentId ) {
     2325                                wp.media.attachment( attachmentId ).fetch().done( function() {
     2326                                        wp.customize.previewer.send( 'site-logo-attachment-data', this.attributes );
     2327                                } );
     2328
     2329                                // Re-render whenever the control's setting changes.
     2330                                control.renderContent();
     2331                        } );
     2332                }
     2333        });
     2334
     2335        /**
    22992336         * @class
    23002337         * @augments wp.customize.Control
    23012338         * @augments wp.customize.Class
     
    32013238                image:         api.ImageControl,
    32023239                cropped_image: api.CroppedImageControl,
    32033240                site_icon:     api.SiteIconControl,
     3241                site_logo:     api.SiteLogoControl,
    32043242                header:        api.HeaderControl,
    32053243                background:    api.BackgroundControl,
    32063244                theme:         api.ThemeControl
  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index 937689b..c0e4fc2 100644
    final class WP_Customize_Manager { 
    217217                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-control.php' );
    218218                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-cropped-image-control.php' );
    219219                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-site-icon-control.php' );
     220                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-site-logo-control.php' );
    220221                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-control.php' );
    221222                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-theme-control.php' );
    222223                require_once( ABSPATH . WPINC . '/customize/class-wp-widget-area-customize-control.php' );
    final class WP_Customize_Manager { 
    18571858                $this->register_control_type( 'WP_Customize_Background_Image_Control' );
    18581859                $this->register_control_type( 'WP_Customize_Cropped_Image_Control' );
    18591860                $this->register_control_type( 'WP_Customize_Site_Icon_Control' );
     1861                $this->register_control_type( 'WP_Customize_Site_Logo_Control' );
    18601862                $this->register_control_type( 'WP_Customize_Theme_Control' );
    18611863
    18621864                /* Themes */
    final class WP_Customize_Manager { 
    19321934                        'section'    => 'title_tagline',
    19331935                ) );
    19341936
     1937                // Add a setting to hide header text if the theme isn't supporting the feature itself.
     1938                // @todo
     1939                if ( ! current_theme_supports( 'custom-header' ) ) {
     1940                        $this->add_setting( 'header_text', array(
     1941                                'default'           => 1,
     1942                                'sanitize_callback' => 'absint',
     1943                                'transport'         => 'postMessage',
     1944                        ) );
     1945
     1946                        $this->add_control( 'header_text', array(
     1947                                'label'    => __( 'Display Site Title and Tagline' ),
     1948                                'section'  => 'title_tagline',
     1949                                'settings' => 'header_text',
     1950                                'type'     => 'checkbox',
     1951                        ) );
     1952                }
     1953
    19351954                $this->add_setting( 'site_icon', array(
    19361955                        'type'       => 'option',
    19371956                        'capability' => 'manage_options',
    final class WP_Customize_Manager { 
    19511970                        'width'       => 512,
    19521971                ) ) );
    19531972
     1973                $this->add_setting( 'site_logo', array(
     1974                        'theme_supports' => array( 'site-logo' ),
     1975                        'type'           => 'option',
     1976                        'capability'     => 'manage_options',
     1977                        'transport'      => 'postMessage',
     1978                ) );
     1979
     1980                $this->add_control( new WP_Customize_Site_Logo_Control( $this, 'site_logo', array(
     1981                        'label'    => __( 'Logo' ),
     1982                        'section'  => 'title_tagline',
     1983                        'priority' => 0,
     1984                ) ) );
     1985
     1986                if ( isset( $this->selective_refresh ) ) {
     1987                        $this->selective_refresh->add_partial( 'site_logo', array(
     1988                                'settings'            => array( 'site_logo' ),
     1989                                'selector'            => '.site-logo-link',
     1990                                'render_callback'     => array( $this, '_render_site_logo_partial' ),
     1991                                'container_inclusive' => true,
     1992                        ) );
     1993                }
     1994
    19541995                /* Colors */
    19551996
    19561997                $this->add_section( 'colors', array(
    final class WP_Customize_Manager { 
    21802221
    21812222                return $color;
    21822223        }
     2224
     2225        /**
     2226         * Callback for rendering the site logo, used in the site_logo partial.
     2227         *
     2228         * This method exists because the partial object and context data are passed
     2229         * into a partial's render_callback so we cannot use get_the_site_logo() as
     2230         * the render_callback directly since it expects a blog ID as the first
     2231         * argument. When WP no longer supports PHP 5.3, this method can be removed
     2232         * in favor of an anonymous function.
     2233         *
     2234         * @see WP_Customize_Manager::register_controls()
     2235         *
     2236         * @since 4.5.0
     2237         * @access private
     2238         */
     2239        public function _render_site_logo_partial() {
     2240                return get_the_site_logo();
     2241        }
    21832242}
    21842243
    21852244/**
  • src/wp-includes/customize/class-wp-customize-site-icon-control.php

    diff --git src/wp-includes/customize/class-wp-customize-site-icon-control.php src/wp-includes/customize/class-wp-customize-site-icon-control.php
    index fe8ac37..4d20f8f 100644
    class WP_Customize_Site_Icon_Control extends WP_Customize_Cropped_Image_Control 
    4141                parent::__construct( $manager, $id, $args );
    4242                add_action( 'customize_controls_print_styles', 'wp_site_icon', 99 );
    4343        }
     44
     45        /**
     46         * Render a JS template for the content of the site icon control.
     47         *
     48         * @since 4.5.0
     49         */
     50        public function content_template() {
     51                ?>
     52                <label for="{{ data.settings['default'] }}-button">
     53                        <# if ( data.label ) { #>
     54                                <span class="customize-control-title">{{ data.label }}</span>
     55                        <# } #>
     56                        <# if ( data.description ) { #>
     57                                <span class="description customize-control-description">{{{ data.description }}}</span>
     58                        <# } #>
     59                </label>
     60
     61                <# if ( data.attachment && data.attachment.id ) { #>
     62                <div class="current">
     63                        <div class="container">
     64                                <div class="attachment-media-view attachment-media-view-{{ data.attachment.type }} {{ data.attachment.orientation }} site-icon-preview">
     65                                        <strong><?php _e( 'As a browser icon' ); ?></strong>
     66                                        <div class="favicon-preview">
     67                                                <img src="images/browser.png" class="browser-preview" width="182" height="" alt="" />
     68
     69                                                <div class="favicon">
     70                                                        <img id="preview-favicon" src="{{ data.attachment.sizes.full.url }}" alt="<?php esc_attr_e( 'Preview as a browser icon' ); ?>"/>
     71                                                </div>
     72                                                <span class="browser-title"><?php bloginfo( 'name' ); ?></span>
     73                                        </div>
     74
     75                                        <strong><?php _e( 'As an app icon' ); ?></strong>
     76                                        <p class="app-icon-preview">
     77                                                <img id="preview-app-icon" src="{{ data.attachment.sizes.full.url }}" alt="<?php esc_attr_e( 'Preview as an app icon' ); ?>"/>
     78                                        </p>
     79                                </div>
     80                        </div>
     81                </div>
     82                <div class="actions">
     83                        <# if ( data.canUpload ) { #>
     84                                <button type="button" class="button remove-button"><?php echo $this->button_labels['remove']; ?></button>
     85                                <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['change']; ?></button>
     86                                <div style="clear:both"></div>
     87                        <# } #>
     88                </div>
     89                <# } else { #>
     90                <div class="current">
     91                        <div class="container">
     92                                <div class="placeholder">
     93                                        <div class="inner">
     94                                                <span><?php echo $this->button_labels['placeholder']; ?></span>
     95                                        </div>
     96                                </div>
     97                        </div>
     98                </div>
     99                <div class="actions">
     100                        <# if ( data.defaultAttachment ) { #>
     101                                <button type="button" class="button default-button"><?php echo $this->button_labels['default']; ?></button>
     102                        <# } #>
     103                        <# if ( data.canUpload ) { #>
     104                                <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['select']; ?></button>
     105                        <# } #>
     106                        <div style="clear:both"></div>
     107                </div>
     108                <# } #>
     109                <?php
     110        }
    44111}
  • new file src/wp-includes/customize/class-wp-customize-site-logo-control.php

    diff --git src/wp-includes/customize/class-wp-customize-site-logo-control.php src/wp-includes/customize/class-wp-customize-site-logo-control.php
    new file mode 100644
    index 0000000..1ad14a8
    - +  
     1<?php
     2/**
     3 * Customize API: WP_Customize_Site_Logo_Control class
     4 *
     5 * @package WordPress
     6 * @subpackage Customize
     7 * @since 4.5.0
     8 */
     9
     10/**
     11 * Customize Site Logo control class.
     12 *
     13 * Used only for custom functionality in JavaScript.
     14 *
     15 * @since 4.5.0
     16 *
     17 * @see WP_Customize_Image_Control
     18 */
     19class WP_Customize_Site_Logo_Control extends WP_Customize_Image_Control {
     20
     21        /**
     22         * Control type.
     23         *
     24         * @since 4.5.0
     25         * @access public
     26         * @var string
     27         */
     28        public $type = 'site_logo';
     29
     30        /**
     31         * Constructor.
     32         *
     33         * @since 4.5.0
     34         * @access public
     35         *
     36         * @param WP_Customize_Manager $manager Customizer bootstrap instance.
     37         * @param string               $id      Control ID.
     38         * @param array                $args    Optional. Arguments to override class property defaults.
     39         */
     40        public function __construct( $manager, $id, $args = array() ) {
     41                parent::__construct( $manager, $id, $args );
     42
     43                $this->button_labels = array(
     44                        'select'       => __( 'Select logo' ),
     45                        'change'       => __( 'Change logo' ),
     46                        'remove'       => __( 'Remove' ),
     47                        'default'      => __( 'Default' ),
     48                        'placeholder'  => __( 'No logo selected' ),
     49                        'frame_title'  => __( 'Select logo' ),
     50                        'frame_button' => __( 'Choose logo' ),
     51                );
     52        }
     53}
  • src/wp-includes/general-template.php

    diff --git src/wp-includes/general-template.php src/wp-includes/general-template.php
    index 1669ae3..27ab304 100644
    function has_site_icon( $blog_id = 0 ) { 
    836836}
    837837
    838838/**
     839 * Whether the site has a Site Logo.
     840 *
     841 * @since 4.5.0
     842 *
     843 * @param int $blog_id Optional. ID of the blog in question. Default current blog.
     844 * @return bool Whether the site has a site logo or not.
     845 */
     846function has_site_logo( $blog_id = 0 ) {
     847        if ( is_multisite() && (int) $blog_id !== get_current_blog_id() ) {
     848                switch_to_blog( $blog_id );
     849        }
     850
     851        $site_logo_id = get_option( 'site_logo' );
     852
     853        if ( is_multisite() && ms_is_switched() ) {
     854                restore_current_blog();
     855        }
     856
     857        return (bool) $site_logo_id;
     858}
     859
     860/**
     861 * Returns a Site Logo, linked to home.
     862 *
     863 * @since 4.5.0
     864 *
     865 * @param int $blog_id Optional. ID of the blog in question. Default current blog.
     866 * @return string Site logo markup.
     867 */
     868function get_the_site_logo( $blog_id = 0 ) {
     869        $html = '';
     870
     871        if ( is_multisite() && (int) $blog_id !== get_current_blog_id() ) {
     872                switch_to_blog( $blog_id );
     873        }
     874
     875        $site_logo_id = get_option( 'site_logo' );
     876
     877        if ( is_multisite() && ms_is_switched() ) {
     878                restore_current_blog();
     879        }
     880        $size = get_theme_support( 'site-logo' );
     881        $size = $size[0]['size'];
     882
     883        // We have a logo. Logo is go.
     884        if ( $site_logo_id ) {
     885                $html = sprintf( '<a href="%1$s" class="site-logo-link" rel="home" itemprop="url">%2$s</a>',
     886                        esc_url( home_url( '/' ) ),
     887                        wp_get_attachment_image( $site_logo_id, $size, false, array(
     888                                'class'     => "site-logo attachment-$size",
     889                                'data-size' => $size,
     890                                'itemprop'  => 'logo',
     891                        ) )
     892                );
     893        }
     894
     895        // If no logo is set but we're in the Customizer, leave a placeholder (needed for the live preview).
     896        elseif ( is_customize_preview() ) {
     897                $html = sprintf( '<a href="%1$s" class="site-logo-link" style="display:none;"><img class="site-logo" data-size="%2$s" /></a>',
     898                        esc_url( home_url( '/' ) ),
     899                        esc_attr( $size )
     900                );
     901        }
     902
     903        /**
     904         * Filter the Site Logo output.
     905         *
     906         * @since 4.5.0
     907         *
     908         * @param string $html Site Logo HTML output.
     909         * @param string $size Size specified in add_theme_support declaration, or 'thumbnail' default.
     910         */
     911        return apply_filters( 'get_the_site_logo', $html, $size );
     912}
     913
     914/**
     915 * Displays a Site Logo, linked to home.
     916 *
     917 * @since 4.5.0
     918 *
     919 * @param int $blog_id Optional. ID of the blog in question. Default current blog.
     920 */
     921function the_site_logo( $blog_id = 0 ) {
     922        echo get_the_site_logo( $blog_id );
     923}
     924
     925/**
    839926 * Returns document title for the current page.
    840927 *
    841928 * @since 4.4.0
  • src/wp-includes/js/customize-preview.js

    diff --git src/wp-includes/js/customize-preview.js src/wp-includes/js/customize-preview.js
    index b6da775..fd3c3ae 100644
     
    223223                        });
    224224                });
    225225
     226                /**
     227                 * Site Logo
     228                 *
     229                 * The site logo setting only contains the attachment ID. To avoid having to send an AJAX request to get more
     230                 * data, we send a separate message with the attachment data we get from the Customizer's media modal.
     231                 * Therefore first callback handles only the event of a new logo being selected.
     232                 *
     233                 * We don't need any information about a removed logo, so the second callback only handles that.
     234                 *
     235                 * @since 4.5.0
     236                 */
     237                api.preview.bind( 'site-logo-attachment-data', function( attachment ) {
     238                        var $logo  = $( '.site-logo' ),
     239                                size   = $logo.data( 'size' ),
     240                                srcset = [];
     241
     242                        // If the source was smaller than the size required by the theme, give the biggest we've got.
     243                        if ( ! attachment.sizes[ size ] ) {
     244                                size = 'full';
     245                        }
     246
     247                        _.each( attachment.sizes, function( size ) {
     248                                srcset.push( size.url + ' ' + size.width + 'w' );
     249                        } );
     250
     251                        $logo.attr( {
     252                                height: attachment.sizes[ size ].height,
     253                                width:  attachment.sizes[ size ].width,
     254                                src:    attachment.sizes[ size ].url,
     255                                srcset: srcset
     256                        } );
     257
     258                        $( '.site-logo-link' ).show();
     259                        $( 'body' ).addClass( 'wp-site-logo' );
     260                } );
     261
     262                api( 'site_logo', function( setting ) {
     263                        setting.bind( function( newValue ) {
     264                                if ( ! newValue ) {
     265                                        $( '.site-logo-link' ).hide();
     266                                        $( 'body' ).removeClass( 'wp-site-logo' );
     267                                }
     268                        } );
     269
     270                        // Focus on the control when the logo is clicked, if there is no site_logo partial.
     271                        if ( ! api.partial || ! api.partial.has( 'site_logo' ) ) {
     272                                $( document.body ).on( 'click', '.site-logo-link', function( e ) {
     273                                        if ( ! e.shiftKey ) {
     274                                                return;
     275                                        }
     276                                        api.preview.send( 'focus-control-for-setting', 'site_logo' );
     277                                } );
     278                                $( '.site-logo-link' ).attr( 'title', 'Shift-click to edit the site logo.' );
     279                        }
     280                } );
     281
    226282                api.trigger( 'preview-ready' );
    227283        });
    228284
  • src/wp-includes/post-template.php

    diff --git src/wp-includes/post-template.php src/wp-includes/post-template.php
    index 5ceed59..6d788ff 100644
    function get_body_class( $class = '' ) { 
    706706        if ( get_background_color() !== get_theme_support( 'custom-background', 'default-color' ) || get_background_image() )
    707707                $classes[] = 'custom-background';
    708708
     709        if ( has_site_logo() ) {
     710                $classes[] = 'wp-site-logo';
     711        }
     712
    709713        $page = $wp_query->get( 'page' );
    710714
    711715        if ( ! $page || $page < 2 )