Make WordPress Core

Changeset 36698


Ignore:
Timestamp:
02/24/2016 10:09:54 PM (8 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.