WordPress.org

Make WordPress Core

Changeset 39241


Ignore:
Timestamp:
11/15/16 09:02:38 (12 months ago)
Author:
westonruter
Message:

Customize: Allow starter content to apply in a new theme when switching from another theme containing changes.

  • Ensure that starter content can apply from theme B after previewing starter content in theme A.
  • Introduce new starter_content flag in changeset setting params which is used to capture whether a value is starter content and thus can be overridden.
  • Create changeset up-front with starter_content flags instead of waiting for AUTOSAVE_INTERVAL.
  • Eliminate instantiation of settings for widget instances in favor of directly calling sanitize_widget_js_instance. This eliminates issues with looking for widgets before they are registered.
  • Ensure that non-placeholders (inline arrays instead of string references) can be supplied in starter content.
  • Re-use auto-draft posts as starter content across theme switches.
  • Introduce starter_content param for WP_Customize_Manager::save_changeset_post() which is false except when starter content is being loaded on a fresh_site.

See #38114.
Fixes #38541.

Location:
trunk/src/wp-includes
Files:
3 edited

Legend:

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

    r39240 r39241  
    524524        } 
    525525 
    526         // Import theme starter content for fresh installs when landing in the customizer and no existing changeset loaded. 
    527         if ( get_option( 'fresh_site' ) && 'customize.php' === $pagenow && ! $this->changeset_post_id() ) { 
     526        /* 
     527         * Import theme starter content for fresh installs when landing in the customizer. 
     528         * Import starter content at after_setup_theme:100 so that any 
     529         * add_theme_support( 'starter-content' ) calls will have been made. 
     530         */ 
     531        if ( get_option( 'fresh_site' ) && 'customize.php' === $pagenow ) { 
    528532            add_action( 'after_setup_theme', array( $this, 'import_theme_starter_content' ), 100 ); 
    529533        } 
     
    886890 
    887891    /** 
    888      * Import theme starter content into post values. 
     892     * Starter content setting IDs. 
     893     * 
     894     * @since 4.7.0 
     895     * @access private 
     896     * @var array 
     897     */ 
     898    protected $starter_content_settings_ids = array(); 
     899 
     900    /** 
     901     * Import theme starter content into the customized state. 
    889902     * 
    890903     * @since 4.7.0 
     
    896909        if ( empty( $starter_content ) ) { 
    897910            $starter_content = get_theme_starter_content(); 
     911        } 
     912 
     913        $changeset_data = array(); 
     914        if ( $this->changeset_post_id() ) { 
     915            $changeset_data = $this->get_changeset_post_data( $this->changeset_post_id() ); 
    898916        } 
    899917 
     
    933951                $setting_id = sprintf( 'widget_%s[%d]', $id_base, $max_widget_numbers[ $id_base ] ); 
    934952 
    935                 $class = 'WP_Customize_Setting'; 
    936  
    937                 /** This filter is documented in wp-includes/class-wp-customize-manager.php */ 
    938                 $args = apply_filters( 'customize_dynamic_setting_args', false, $setting_id ); 
    939  
    940                 if ( false !== $args ) { 
    941  
    942                     /** This filter is documented in wp-includes/class-wp-customize-manager.php */ 
    943                     $class = apply_filters( 'customize_dynamic_setting_class', $class, $setting_id, $args ); 
    944  
    945                     $setting = new $class( $this, $setting_id, $args ); 
    946                     $setting_value = call_user_func( $setting->sanitize_js_callback, $instance, $setting ); 
     953                $setting_value = $this->widgets->sanitize_widget_js_instance( $instance ); 
     954                if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) { 
    947955                    $this->set_post_value( $setting_id, $setting_value ); 
    948                     $sidebar_widget_ids[] = $widget_id; 
     956                    $this->starter_content_settings_ids[] = $setting_id; 
    949957                } 
    950             } 
    951  
    952             $this->set_post_value( sprintf( 'sidebars_widgets[%s]', $sidebar_id ), $sidebar_widget_ids ); 
     958                $sidebar_widget_ids[] = $widget_id; 
     959            } 
     960 
     961            $setting_id = sprintf( 'sidebars_widgets[%s]', $sidebar_id ); 
     962            if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) { 
     963                $this->set_post_value( $setting_id, $sidebar_widget_ids ); 
     964                $this->starter_content_settings_ids[] = $setting_id; 
     965            } 
    953966        } 
    954967 
    955968        // Posts & pages. 
    956969        if ( ! empty( $posts ) ) { 
     970            $nav_menus_created_posts = array(); 
     971            if ( ! empty( $changeset_data['nav_menus_created_posts']['value'] ) ) { 
     972                $nav_menus_created_posts = $changeset_data['nav_menus_created_posts']['value']; 
     973            } 
     974 
     975            $existing_posts = array(); 
     976            if ( ! empty( $nav_menus_created_posts ) ) { 
     977                $existing_posts_query = new WP_Query( array( 
     978                    'post__in' => $nav_menus_created_posts, 
     979                    'post_status' => 'auto-draft', 
     980                    'post_type' => 'any', 
     981                    'number' => -1, 
     982                ) ); 
     983                foreach ( $existing_posts_query->posts as $existing_post ) { 
     984                    $existing_posts[ $existing_post->post_type . ':' . $existing_post->post_name ] = $existing_post; 
     985                } 
     986            } 
     987 
    957988            foreach ( array_keys( $posts ) as $post_symbol ) { 
     989                if ( empty( $posts[ $post_symbol ]['post_type'] ) ) { 
     990                    continue; 
     991                } 
     992                $post_type = $posts[ $post_symbol ]['post_type']; 
     993                if ( ! empty( $posts[ $post_symbol ]['post_name'] ) ) { 
     994                    $post_name = $posts[ $post_symbol ]['post_name']; 
     995                } elseif ( ! empty( $posts[ $post_symbol ]['post_title'] ) ) { 
     996                    $post_name = sanitize_title( $posts[ $post_symbol ]['post_title'] ); 
     997                } else { 
     998                    continue; 
     999                } 
     1000 
     1001                // Use existing auto-draft post if one already exists with the same type and name. 
     1002                if ( isset( $existing_posts[ $post_type . ':' . $post_name ] ) ) { 
     1003                    $posts[ $post_symbol ]['ID'] = $existing_posts[ $post_type . ':' . $post_name ]->ID; 
     1004                    continue; 
     1005                } 
     1006 
    9581007                $r = $this->nav_menus->insert_auto_draft_post( $posts[ $post_symbol ] ); 
    9591008                if ( $r instanceof WP_Post ) { 
     
    9611010                } 
    9621011            } 
    963             $this->set_post_value( 'nav_menus_created_posts', wp_list_pluck( $posts, 'ID' ) ); // This is why nav_menus component is dependency for adding posts. 
     1012 
     1013            // The nav_menus_created_posts setting is why nav_menus component is dependency for adding posts. 
     1014            $setting_id = 'nav_menus_created_posts'; 
     1015            if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) { 
     1016                $nav_menus_created_posts = array_unique( array_merge( $nav_menus_created_posts, wp_list_pluck( $posts, 'ID' ) ) ); 
     1017                $this->set_post_value( $setting_id, array_values( $nav_menus_created_posts ) ); 
     1018                $this->starter_content_settings_ids[] = $setting_id; 
     1019            } 
    9641020        } 
    9651021 
    9661022        // Nav menus. 
    9671023        $placeholder_id = -1; 
     1024        $reused_nav_menu_setting_ids = array(); 
    9681025        foreach ( $nav_menus as $nav_menu_location => $nav_menu ) { 
    969             $nav_menu_term_id = $placeholder_id--; 
    970             $nav_menu_setting_id = sprintf( 'nav_menu[%d]', $nav_menu_term_id ); 
     1026 
     1027            $nav_menu_term_id = null; 
     1028            $nav_menu_setting_id = null; 
     1029            $matches = array(); 
     1030 
     1031            // Look for an existing placeholder menu with starter content to re-use. 
     1032            foreach ( $changeset_data as $setting_id => $setting_params ) { 
     1033                $can_reuse = ( 
     1034                    ! empty( $setting_params['starter_content'] ) 
     1035                    && 
     1036                    ! in_array( $setting_id, $reused_nav_menu_setting_ids, true ) 
     1037                    && 
     1038                    preg_match( '#^nav_menu\[(?P<nav_menu_id>-?\d+)\]$#', $setting_id, $matches ) 
     1039                ); 
     1040                if ( $can_reuse ) { 
     1041                    $nav_menu_term_id = intval( $matches['nav_menu_id'] ); 
     1042                    $nav_menu_setting_id = $setting_id; 
     1043                    $reused_nav_menu_setting_ids[] = $setting_id; 
     1044                    break; 
     1045                } 
     1046            } 
     1047 
     1048            if ( ! $nav_menu_term_id ) { 
     1049                while ( isset( $changeset_data[ sprintf( 'nav_menu[%d]', $placeholder_id ) ] ) ) { 
     1050                    $placeholder_id--; 
     1051                } 
     1052                $nav_menu_term_id = $placeholder_id; 
     1053                $nav_menu_setting_id = sprintf( 'nav_menu[%d]', $placeholder_id ); 
     1054            } 
     1055 
    9711056            $this->set_post_value( $nav_menu_setting_id, array( 
    9721057                'name' => isset( $nav_menu['name'] ) ? $nav_menu['name'] : $nav_menu_location, 
    9731058            ) ); 
     1059            $this->starter_content_settings_ids[] = $nav_menu_setting_id; 
    9741060 
    9751061            // @todo Add support for menu_item_parent. 
     
    9951081                    $nav_menu_item['object_id'] = 0; 
    9961082                } 
    997                 $this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item ); 
    998             } 
    999  
    1000             $this->set_post_value( sprintf( 'nav_menu_locations[%s]', $nav_menu_location ), $nav_menu_term_id ); 
     1083 
     1084                if ( empty( $changeset_data[ $nav_menu_item_setting_id ] ) || ! empty( $changeset_data[ $nav_menu_item_setting_id ]['starter_content'] ) ) { 
     1085                    $this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item ); 
     1086                    $this->starter_content_settings_ids[] = $nav_menu_item_setting_id; 
     1087                } 
     1088            } 
     1089 
     1090            $setting_id = sprintf( 'nav_menu_locations[%s]', $nav_menu_location ); 
     1091            if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) { 
     1092                $this->set_post_value( $setting_id, $nav_menu_term_id ); 
     1093                $this->starter_content_settings_ids[] = $setting_id; 
     1094            } 
    10011095        } 
    10021096 
     
    10061100                $value = $posts[ $matches['symbol'] ]['ID']; 
    10071101            } 
    1008             $this->set_post_value( $name, $value ); 
     1102 
     1103            if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) { 
     1104                $this->set_post_value( $name, $value ); 
     1105                $this->starter_content_settings_ids[] = $name; 
     1106            } 
    10091107        } 
    10101108 
     
    10141112                $value = $posts[ $matches['symbol'] ]['ID']; 
    10151113            } 
    1016             $this->set_post_value( $name, $value ); 
    1017         } 
     1114 
     1115            if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) { 
     1116                $this->set_post_value( $name, $value ); 
     1117                $this->starter_content_settings_ids[] = $name; 
     1118            } 
     1119        } 
     1120 
     1121        if ( ! empty( $this->starter_content_settings_ids ) ) { 
     1122            if ( did_action( 'customize_register' ) ) { 
     1123                $this->_save_starter_content_changeset(); 
     1124            } else { 
     1125                add_action( 'customize_register', array( $this, '_save_starter_content_changeset' ), 1000 ); 
     1126            } 
     1127        } 
     1128    } 
     1129 
     1130    /** 
     1131     * Save starter content changeset. 
     1132     * 
     1133     * @since 4.7.0 
     1134     * @access private 
     1135     */ 
     1136    public function _save_starter_content_changeset() { 
     1137 
     1138        if ( empty( $this->starter_content_settings_ids ) ) { 
     1139            return; 
     1140        } 
     1141 
     1142        $this->save_changeset_post( array( 
     1143            'data' => array_fill_keys( $this->starter_content_settings_ids, array( 'starter_content' => true ) ), 
     1144            'starter_content' => true, 
     1145        ) ); 
    10181146    } 
    10191147 
     
    18241952     *     Args for changeset post. 
    18251953     * 
    1826      *     @type array  $data     Optional additional changeset data. Values will be merged on top of any existing post values. 
    1827      *     @type string $status   Post status. Optional. If supplied, the save will be transactional and a post revision will be allowed. 
    1828      *     @type string $title    Post title. Optional. 
    1829      *     @type string $date_gmt Date in GMT. Optional. 
    1830      *     @type int    $user_id  ID for user who is saving the changeset. Optional, defaults to the current user ID. 
     1954     *     @type array  $data            Optional additional changeset data. Values will be merged on top of any existing post values. 
     1955     *     @type string $status          Post status. Optional. If supplied, the save will be transactional and a post revision will be allowed. 
     1956     *     @type string $title           Post title. Optional. 
     1957     *     @type string $date_gmt        Date in GMT. Optional. 
     1958     *     @type int    $user_id         ID for user who is saving the changeset. Optional, defaults to the current user ID. 
     1959     *     @type bool   $starter_content Whether the data is starter content. If false (default), then $starter_content will be cleared for any $data being saved. 
    18311960     * } 
    18321961     * 
     
    18421971                'date_gmt' => null, 
    18431972                'user_id' => get_current_user_id(), 
     1973                'starter_content' => false, 
    18441974            ), 
    18451975            $args 
     
    19782108                    $data[ $changeset_setting_id ] = array(); 
    19792109                } 
     2110 
    19802111                $data[ $changeset_setting_id ] = array_merge( 
    19812112                    $data[ $changeset_setting_id ], 
     
    19862117                    ) 
    19872118                ); 
     2119 
     2120                // Clear starter_content flag in data if changeset is not explicitly being updated for starter content. 
     2121                if ( empty( $args['starter_content'] ) ) { 
     2122                    unset( $data[ $changeset_setting_id ]['starter_content'] ); 
     2123                } 
    19882124            } 
    19892125        } 
  • trunk/src/wp-includes/class-wp-customize-nav-menus.php

    r39138 r39241  
    697697        $this->manager->add_setting( new WP_Customize_Filter_Setting( $this->manager, 'nav_menus_created_posts', array( 
    698698            'transport' => 'postMessage', 
     699            'type' => 'option', // To prevent theme prefix in changeset. 
    699700            'default' => array(), 
    700701            'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ), 
  • trunk/src/wp-includes/theme.php

    r39240 r39241  
    18251825    } 
    18261826 
    1827     $core_content = array ( 
     1827    $core_content = array( 
    18281828        'widgets' => array( 
    1829             'text_business_info' => array ( 'text', array ( 
     1829            'text_business_info' => array( 'text', array( 
    18301830                'title' => _x( 'Find Us', 'Theme starter content' ), 
    1831                 'text' => join( '', array ( 
     1831                'text' => join( '', array( 
    18321832                    '<p><strong>' . _x( 'Address', 'Theme starter content' ) . '</strong><br />', 
    18331833                    _x( '123 Main Street', 'Theme starter content' ) . '<br />' . _x( 'New York, NY 10001', 'Theme starter content' ) . '</p>', 
     
    18361836                ) ), 
    18371837            ) ), 
    1838             'search' => array ( 'search', array ( 
     1838            'search' => array( 'search', array( 
    18391839                'title' => _x( 'Site Search', 'Theme starter content' ), 
    18401840            ) ), 
    1841             'text_credits' => array ( 'text', array ( 
     1841            'text_credits' => array( 'text', array( 
    18421842                'title' => _x( 'Site Credits', 'Theme starter content' ), 
    18431843                'text' => sprintf( _x( 'This site was created on %s', 'Theme starter content' ), get_date_from_gmt( current_time( 'mysql', 1 ), 'c' ) ), 
    18441844            ) ), 
    18451845        ), 
    1846         'nav_menus' => array ( 
     1846        'nav_menus' => array( 
    18471847            'page_home' => array( 
    18481848                'type' => 'post_type', 
     
    19201920    foreach ( $config as $type => $args ) { 
    19211921        switch( $type ) { 
    1922             // Use options and theme_mods as-is 
     1922            // Use options and theme_mods as-is. 
    19231923            case 'options' : 
    19241924            case 'theme_mods' : 
     
    19261926                break; 
    19271927 
    1928             // Widgets are an extra level down due to groupings 
     1928            // Widgets are grouped into sidebars. 
    19291929            case 'widgets' : 
    1930                 foreach ( $config[ $type ] as $group => $items ) { 
    1931                     foreach ( $items as $id ) { 
    1932                         if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) { 
    1933                             $content[ $type ][ $group ][ $id ] = $core_content[ $type ][ $id ]; 
     1930                foreach ( $config[ $type ] as $sidebar_id => $widgets ) { 
     1931                    foreach ( $widgets as $widget ) { 
     1932                        if ( is_array( $widget ) ) { 
     1933                            $content[ $type ][ $sidebar_id ][] = $widget; 
     1934                        } elseif ( is_string( $widget ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $widget ] ) ) { 
     1935                            $content[ $type ][ $sidebar_id ][] = $core_content[ $type ][ $widget ]; 
    19341936                        } 
    19351937                    } 
     
    19371939                break; 
    19381940 
    1939             // And nav menus are yet another level down 
     1941            // And nav menu items are grouped into nav menus. 
    19401942            case 'nav_menus' : 
    1941                 foreach ( $config[ $type ] as $group => $args2 ) { 
    1942                     // Menu groups need a name 
    1943                     if ( empty( $args['name'] ) ) { 
    1944                         $args2['name'] = $group; 
     1943                foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) { 
     1944 
     1945                    // Ensure nav menus get a name. 
     1946                    if ( empty( $nav_menu['name'] ) ) { 
     1947                        $nav_menu['name'] = $nav_menu_location; 
    19451948                    } 
    19461949 
    1947                     $content[ $type ][ $group ]['name'] = $args2['name']; 
    1948  
    1949                     // Do we need to check if this is empty? 
    1950                     foreach ( $args2['items'] as $id ) { 
    1951                         if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) { 
    1952                             $content[ $type ][ $group ]['items'][ $id ] = $core_content[ $type ][ $id ]; 
     1950                    $content[ $type ][ $nav_menu_location ]['name'] = $nav_menu['name']; 
     1951 
     1952                    foreach ( $nav_menu['items'] as $nav_menu_item ) { 
     1953                        if ( is_array( $nav_menu_item ) ) { 
     1954                            $content[ $type ][ $nav_menu_location ]['items'][] = $nav_menu_item; 
     1955                        } elseif ( is_string( $nav_menu_item ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $nav_menu_item ] ) ) { 
     1956                            $content[ $type ][ $nav_menu_location ]['items'][] = $core_content[ $type ][ $nav_menu_item ]; 
    19531957                        } 
    19541958                    } 
     
    19561960                break; 
    19571961 
    1958  
    1959             // Everything else should map at the next level 
     1962            // Everything else should map at the next level. 
    19601963            default : 
    1961                 foreach( $config[ $type ] as $id ) { 
    1962                     if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) { 
    1963                         $content[ $type ][ $id ] = $core_content[ $type ][ $id ]; 
     1964                foreach( $config[ $type ] as $i => $item ) { 
     1965                    if ( is_array( $item ) ) { 
     1966                        $content[ $type ][ $i ] = $item; 
     1967                    } elseif ( is_string( $item ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $item ] ) ) { 
     1968                        $content[ $type ][ $item ] = $core_content[ $type ][ $item ]; 
    19641969                    } 
    19651970                } 
Note: See TracChangeset for help on using the changeset viewer.