Make WordPress Core

Changeset 36698


Ignore:
Timestamp:
02/24/2016 10:09:54 PM (11 years ago)
Author:
obenland
Message:

Customize: Introduce Logo support for themes.

Allows a common theme feature to have a common implementation provided by core and available in a consistent location for users.
See https://make.wordpress.org/core/2016/02/24/theme-logo-support/

Props kwight, enejb, jeherve, bhubbard, samhotchkiss, zinigor, eliorivero, adamsilverstein, melchoyce, ryan, mikeschroder, westonruter, pento, karmatosed, celloexpressions, obenland.
See #33755.

Location:
trunk/src
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/customize-controls.css

    r36641 r36698  
    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;
     
    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 {
     
    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;
     
    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;
     
    821827.customize-control-cropped_image .inner,
    822828.customize-control-site_icon .inner,
     829.customize-control-site_logo .inner,
    823830.customize-control-header .inner {
    824831        display: none;
     
    836843.customize-control-cropped_image .inner,
    837844.customize-control-site_icon .inner,
     845.customize-control-site_logo .inner,
    838846.customize-control-image .inner {
    839847        display: block;
     
    847855.customize-control-cropped_image .inner,
    848856.customize-control-site_icon .inner,
     857.customize-control-site_logo.inner,
    849858.customize-control-header .inner,
    850859.customize-control-header .inner .dashicons {
     
    990999.customize-control-site_icon .remove-button,
    9911000.customize-control-site_icon .default-button,
     1001.customize-control-site_logo .remove-button,
     1002.customize-control-site_logo .default-button,
    9921003.customize-control-header .remove {
    9931004        float: left;
     
    10011012.customize-control-cropped_image .upload-button,
    10021013.customize-control-site_icon .upload-button,
     1014.customize-control-site_logo .upload-button,
    10031015.customize-control-header .new {
    10041016        float: right;
  • trunk/src/wp-admin/includes/admin.php

    r35740 r36698  
    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');
  • trunk/src/wp-admin/includes/template.php

    r36642 r36698  
    17511751        }
    17521752
     1753        if ( $post->ID == get_theme_mod( 'site_logo' ) ) {
     1754                $media_states[] = __( 'Logo' );
     1755        }
     1756
    17531757        /**
    17541758         * Filter the default media display states for items in the Media list table.
     
    17571761         *
    17581762         * @param array $media_states An array of media states. Default 'Header Image',
    1759          *                            'Background Image', 'Site Icon'.
     1763         *                            'Background Image', 'Site Icon', 'Logo'.
    17601764         */
    17611765        $media_states = apply_filters( 'display_media_states', $media_states );
  • trunk/src/wp-admin/js/customize-controls.js

    r36689 r36698  
    23042304
    23052305        /**
     2306         * A control for selecting Site Logos.
     2307         *
     2308         * @class
     2309         * @augments wp.customize.MediaControl
     2310         * @augments wp.customize.Control
     2311         * @augments wp.customize.Class
     2312         */
     2313        api.SiteLogoControl = api.MediaControl.extend({
     2314
     2315                /**
     2316                 * When the control's DOM structure is ready,
     2317                 * set up internal event bindings.
     2318                 */
     2319                ready: function() {
     2320                        var control = this;
     2321
     2322                        // Shortcut so that we don't have to use _.bind every time we add a callback.
     2323                        _.bindAll( control, 'restoreDefault', 'removeFile', 'openFrame', 'select' );
     2324
     2325                        // Bind events, with delegation to facilitate re-rendering.
     2326                        control.container.on( 'click keydown', '.upload-button', control.openFrame );
     2327                        control.container.on( 'click keydown', '.thumbnail-image img', control.openFrame );
     2328                        control.container.on( 'click keydown', '.default-button', control.restoreDefault );
     2329                        control.container.on( 'click keydown', '.remove-button', control.removeFile );
     2330
     2331                        control.setting.bind( function( attachmentId ) {
     2332                                wp.media.attachment( attachmentId ).fetch().done( function() {
     2333                                        wp.customize.previewer.send( 'site-logo-attachment-data', this.attributes );
     2334                                } );
     2335
     2336                                // Re-render whenever the control's setting changes.
     2337                                control.renderContent();
     2338                        } );
     2339                }
     2340        });
     2341
     2342        /**
    23062343         * @class
    23072344         * @augments wp.customize.Control
     
    32093246                cropped_image: api.CroppedImageControl,
    32103247                site_icon:     api.SiteIconControl,
     3248                site_logo:     api.SiteLogoControl,
    32113249                header:        api.HeaderControl,
    32123250                background:    api.BackgroundControl,
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r36687 r36698  
    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' );
     
    829830                        'activeControls' => array(),
    830831                        'nonce' => $this->get_nonces(),
     832                        'l10n' => array(
     833                                'shiftClickToEdit' => __( 'Shift-click to edit this element.' ),
     834                        ),
    831835                        '_dirty' => array_keys( $this->unsanitized_post_values() ),
    832836                );
     
    18581862                $this->register_control_type( 'WP_Customize_Cropped_Image_Control' );
    18591863                $this->register_control_type( 'WP_Customize_Site_Icon_Control' );
     1864                $this->register_control_type( 'WP_Customize_Site_Logo_Control' );
    18601865                $this->register_control_type( 'WP_Customize_Theme_Control' );
    18611866
     
    19321937                        'section'    => 'title_tagline',
    19331938                ) );
     1939
     1940                // Add a setting to hide header text if the theme isn't supporting the feature itself.
     1941                // @todo
     1942                if ( ! current_theme_supports( 'custom-header' ) ) {
     1943                        $this->add_setting( 'header_text', array(
     1944                                'default'           => 1,
     1945                                'sanitize_callback' => 'absint',
     1946                                'transport'         => 'postMessage',
     1947                        ) );
     1948
     1949                        $this->add_control( 'header_text', array(
     1950                                'label'    => __( 'Display Site Title and Tagline' ),
     1951                                'section'  => 'title_tagline',
     1952                                'settings' => 'header_text',
     1953                                'type'     => 'checkbox',
     1954                        ) );
     1955                }
    19341956
    19351957                $this->add_setting( 'site_icon', array(
     
    19521974                ) ) );
    19531975
     1976                $this->add_setting( 'site_logo', array(
     1977                        'theme_supports' => array( 'site-logo' ),
     1978                        'transport'      => 'postMessage',
     1979                ) );
     1980
     1981                $this->add_control( new WP_Customize_Site_Logo_Control( $this, 'site_logo', array(
     1982                        'label'    => __( 'Logo' ),
     1983                        'section'  => 'title_tagline',
     1984                        'priority' => 0,
     1985                ) ) );
     1986
     1987                if ( isset( $this->selective_refresh ) ) {
     1988                        $this->selective_refresh->add_partial( 'site_logo', array(
     1989                                'settings'            => array( 'site_logo' ),
     1990                                'selector'            => '.site-logo-link',
     1991                                'render_callback'     => array( $this, '_render_site_logo_partial' ),
     1992                                'container_inclusive' => true,
     1993                        ) );
     1994                }
     1995
    19541996                /* Colors */
    19551997
     
    21802222
    21812223                return $color;
     2224        }
     2225
     2226        /**
     2227         * Callback for rendering the site logo, used in the site_logo partial.
     2228         *
     2229         * This method exists because the partial object and context data are passed
     2230         * into a partial's render_callback so we cannot use get_the_site_logo() as
     2231         * the render_callback directly since it expects a blog ID as the first
     2232         * argument. When WP no longer supports PHP 5.3, this method can be removed
     2233         * in favor of an anonymous function.
     2234         *
     2235         * @see WP_Customize_Manager::register_controls()
     2236         *
     2237         * @since 4.5.0
     2238         * @access private
     2239         *
     2240         * @return string Site logo.
     2241         */
     2242        public function _render_site_logo_partial() {
     2243                return get_the_site_logo();
    21822244        }
    21832245}
  • trunk/src/wp-includes/customize/class-wp-customize-site-icon-control.php

    r35389 r36698  
    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}
  • trunk/src/wp-includes/general-template.php

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

    r36414 r36698  
    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.selectiveRefresh || ! api.selectiveRefresh.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', api.settings.l10n.shiftClickToEdit );
     279                        }
     280                } );
     281
    226282                api.trigger( 'preview-ready' );
    227283        });
  • trunk/src/wp-includes/post-template.php

    r36685 r36698  
    706706        if ( get_background_color() !== get_theme_support( 'custom-background', 'default-color' ) || get_background_image() )
    707707                $classes[] = 'custom-background';
     708
     709        if ( has_site_logo() ) {
     710                $classes[] = 'wp-site-logo';
     711        }
    708712
    709713        $page = $wp_query->get( 'page' );
Note: See TracChangeset for help on using the changeset viewer.