Make WordPress Core


Ignore:
Timestamp:
10/28/2016 02:56:16 AM (9 years ago)
Author:
westonruter
Message:

Customize: Introduce starter content and site freshness state.

A theme can opt-in for tailored starter content to apply to the customizer when previewing the theme on a fresh install, when fresh_site is at its initial 1 value. Starter content is staged in the customizer and does not go live unless the changes are published. Initial starter content is added to Twenty Seventeen.

  • The fresh_site flag is cleared when a published post or page is saved, when widgets are modified, or when the customizer state is saved.
  • Starter content is registered via starter-content theme support, where the argument is an array containing widgets, posts, nav_menus, options, and theme_mods. Posts/pages in starter content are created with the auto-draft status, re-using the page/post stubs feature added to nav menus and the static front page controls.
  • A get_theme_starter_content filter allows for plugins to extend a theme's starter content.
  • Starter content in themes can/should re-use existing starter content items in core by using named placeholders.
  • Import theme starter content into customized state when fresh site.
  • Prevent original_title differences from causing refreshes if title is present.
  • Ensure nav menu item url is set according to object when previewing.
  • Make sure initial saved state is false if there are dirty settings without an existing changeset.
  • Ensure dirty settings are cleaned upon changeset publishing.

Props helen, westonruter, ocean90.
Fixes #38114, #38533.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r38989 r38991  
    532532        }
    533533
     534        // Import theme starter content for fresh installs when landing in the customizer and no existing changeset loaded.
     535        if ( get_option( 'fresh_site' ) && 'customize.php' === $pagenow && ! $this->changeset_post_id() ) {
     536            add_action( 'after_setup_theme', array( $this, 'import_theme_starter_content' ), 100 );
     537        }
     538
    534539        $this->start_previewing_theme();
    535540    }
     
    886891        }
    887892        return $this->_changeset_data;
     893    }
     894
     895    /**
     896     * Import theme starter content into post values.
     897     *
     898     * @since 4.7.0
     899     * @access public
     900     *
     901     * @param array $starter_content Starter content. Defaults to `get_theme_starter_content()`.
     902     */
     903    function import_theme_starter_content( $starter_content = array() ) {
     904        if ( empty( $starter_content ) ) {
     905            $starter_content = get_theme_starter_content();
     906        }
     907
     908        $sidebars_widgets = isset( $starter_content['widgets'] ) && ! empty( $this->widgets ) ? $starter_content['widgets'] : array();
     909        $posts = isset( $starter_content['posts'] ) && ! empty( $this->nav_menus ) ? $starter_content['posts'] : array();
     910        $options = isset( $starter_content['options'] ) ? $starter_content['options'] : array();
     911        $nav_menus = isset( $starter_content['nav_menus'] ) && ! empty( $this->nav_menus ) ? $starter_content['nav_menus'] : array();
     912        $theme_mods = isset( $starter_content['theme_mods'] ) ? $starter_content['theme_mods'] : array();
     913
     914        // Widgets.
     915        $max_widget_numbers = array();
     916        foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
     917            $sidebar_widget_ids = array();
     918            foreach ( $widgets as $widget ) {
     919                list( $id_base, $instance ) = $widget;
     920
     921                if ( ! isset( $max_widget_numbers[ $id_base ] ) ) {
     922
     923                    // When $settings is an array-like object, get an intrinsic array for use with array_keys().
     924                    $settings = get_option( "widget_{$id_base}", array() );
     925                    if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
     926                        $settings = $settings->getArrayCopy();
     927                    }
     928
     929                    // Find the max widget number for this type.
     930                    $widget_numbers = array_keys( $settings );
     931                    $widget_numbers[] = 1;
     932                    $max_widget_numbers[ $id_base ] = call_user_func_array( 'max', $widget_numbers );
     933                }
     934                $max_widget_numbers[ $id_base ] += 1;
     935
     936                $widget_id = sprintf( '%s-%d', $id_base, $max_widget_numbers[ $id_base ] );
     937                $setting_id = sprintf( 'widget_%s[%d]', $id_base, $max_widget_numbers[ $id_base ] );
     938
     939                $class = 'WP_Customize_Setting';
     940
     941                /** This filter is documented in wp-includes/class-wp-customize-manager.php */
     942                $args = apply_filters( 'customize_dynamic_setting_args', false, $setting_id );
     943
     944                if ( false !== $args ) {
     945
     946                    /** This filter is documented in wp-includes/class-wp-customize-manager.php */
     947                    $class = apply_filters( 'customize_dynamic_setting_class', $class, $setting_id, $args );
     948
     949                    $setting = new $class( $this, $setting_id, $args );
     950                    $setting_value = call_user_func( $setting->sanitize_js_callback, $instance, $setting );
     951                    $this->set_post_value( $setting_id, $setting_value );
     952                    $sidebar_widget_ids[] = $widget_id;
     953                }
     954            }
     955
     956            $this->set_post_value( sprintf( 'sidebars_widgets[%s]', $sidebar_id ), $sidebar_widget_ids );
     957        }
     958
     959        // Posts & pages.
     960        if ( ! empty( $posts ) ) {
     961            foreach ( array_keys( $posts ) as $post_symbol ) {
     962                $posts[ $post_symbol ]['ID'] = wp_insert_post( wp_slash( array_merge(
     963                    $posts[ $post_symbol ],
     964                    array( 'post_status' => 'auto-draft' )
     965                ) ) );
     966            }
     967            $this->set_post_value( 'nav_menus_created_posts', wp_list_pluck( $posts, 'ID' ) ); // This is why nav_menus component is dependency for adding posts.
     968        }
     969
     970        // Nav menus.
     971        $placeholder_id = -1;
     972        foreach ( $nav_menus as $nav_menu_location => $nav_menu ) {
     973            $nav_menu_term_id = $placeholder_id--;
     974            $nav_menu_setting_id = sprintf( 'nav_menu[%d]', $nav_menu_term_id );
     975            $this->set_post_value( $nav_menu_setting_id, array(
     976                'name' => isset( $nav_menu['name'] ) ? $nav_menu['name'] : $nav_menu_location,
     977            ) );
     978
     979            // @todo Add support for menu_item_parent.
     980            $position = 0;
     981            foreach ( $nav_menu['items'] as $nav_menu_item ) {
     982                $nav_menu_item_setting_id = sprintf( 'nav_menu_item[%d]', $placeholder_id-- );
     983                if ( ! isset( $nav_menu_item['position'] ) ) {
     984                    $nav_menu_item['position'] = $position++;
     985                }
     986                $nav_menu_item['nav_menu_term_id'] = $nav_menu_term_id;
     987
     988                if ( isset( $nav_menu_item['object_id'] ) ) {
     989                    if ( 'post_type' === $nav_menu_item['type'] && preg_match( '/^{{(?P<symbol>.+)}}$/', $nav_menu_item['object_id'], $matches ) && isset( $posts[ $matches['symbol'] ] ) ) {
     990                        $nav_menu_item['object_id'] = $posts[ $matches['symbol'] ]['ID'];
     991                        if ( empty( $nav_menu_item['title'] ) ) {
     992                            $original_object = get_post( $nav_menu_item['object_id'] );
     993                            $nav_menu_item['title'] = $original_object->post_title;
     994                        }
     995                    } else {
     996                        continue;
     997                    }
     998                } else {
     999                    $nav_menu_item['object_id'] = 0;
     1000                }
     1001                $this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item );
     1002            }
     1003
     1004            $this->set_post_value( sprintf( 'nav_menu_locations[%s]', $nav_menu_location ), $nav_menu_term_id );
     1005        }
     1006
     1007        // Options.
     1008        foreach ( $options as $name => $value ) {
     1009            if ( preg_match( '/^{{(?P<symbol>.+)}}$/', $value, $matches ) && isset( $posts[ $matches['symbol'] ] ) ) {
     1010                $value = $posts[ $matches['symbol'] ]['ID'];
     1011            }
     1012            $this->set_post_value( $name, $value );
     1013        }
     1014
     1015        // Theme mods.
     1016        foreach ( $theme_mods as $name => $value ) {
     1017            if ( preg_match( '/^{{(?P<symbol>.+)}}$/', $value, $matches ) && isset( $posts[ $matches['symbol'] ] ) ) {
     1018                $value = $posts[ $matches['symbol'] ]['ID'];
     1019            }
     1020            $this->set_post_value( $name, $value );
     1021        }
    8881022    }
    8891023
Note: See TracChangeset for help on using the changeset viewer.