<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[39276] trunk: Customize: Add unit tests for importing theme starter content.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/39276">39276</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/39276","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>westonruter</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2016-11-17 08:17:57 +0000 (Thu, 17 Nov 2016)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Customize: Add unit tests for importing theme starter content.

Props welcher, westonruter.
See <a href="https://core.trac.wordpress.org/ticket/38114">#38114</a>, <a href="https://core.trac.wordpress.org/ticket/38533">#38533</a>, <a href="https://core.trac.wordpress.org/ticket/38615">#38615</a>.
Fixes <a href="https://core.trac.wordpress.org/ticket/38540">#38540</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpcustomizemanagerphp">trunk/src/wp-includes/class-wp-customize-manager.php</a></li>
<li><a href="#trunksrcwpincludesthemephp">trunk/src/wp-includes/theme.php</a></li>
<li><a href="#trunktestsphpunittestscustomizemanagerphp">trunk/tests/phpunit/tests/customize/manager.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsphpunitteststhemegetThemeStarterContentphp">trunk/tests/phpunit/tests/theme/getThemeStarterContent.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpcustomizemanagerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-customize-manager.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-customize-manager.php      2016-11-17 04:20:22 UTC (rev 39275)
+++ trunk/src/wp-includes/class-wp-customize-manager.php        2016-11-17 08:17:57 UTC (rev 39276)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -895,7 +895,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @access private
</span><span class="cx" style="display: block; padding: 0 10px">         * @var array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        protected $starter_content_settings_ids = array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected $pending_starter_content_settings_ids = array();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Import theme starter content into the customized state.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -953,7 +953,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $setting_value = $this->widgets->sanitize_widget_js_instance( $instance );
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $this->set_post_value( $setting_id, $setting_value );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $this->starter_content_settings_ids[] = $setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $this->pending_starter_content_settings_ids[] = $setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><span class="cx" style="display: block; padding: 0 10px">                                $sidebar_widget_ids[] = $widget_id;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -961,7 +961,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting_id = sprintf( 'sidebars_widgets[%s]', $sidebar_id );
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->set_post_value( $setting_id, $sidebar_widget_ids );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->starter_content_settings_ids[] = $setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->pending_starter_content_settings_ids[] = $setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1015,7 +1015,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $nav_menus_created_posts = array_unique( array_merge( $nav_menus_created_posts, wp_list_pluck( $posts, 'ID' ) ) );
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->set_post_value( $setting_id, array_values( $nav_menus_created_posts ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->starter_content_settings_ids[] = $setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->pending_starter_content_settings_ids[] = $setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1056,7 +1056,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->set_post_value( $nav_menu_setting_id, array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'name' => isset( $nav_menu['name'] ) ? $nav_menu['name'] : $nav_menu_location,
</span><span class="cx" style="display: block; padding: 0 10px">                        ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->starter_content_settings_ids[] = $nav_menu_setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->pending_starter_content_settings_ids[] = $nav_menu_setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // @todo Add support for menu_item_parent.
</span><span class="cx" style="display: block; padding: 0 10px">                        $position = 0;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1083,14 +1083,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( empty( $changeset_data[ $nav_menu_item_setting_id ] ) || ! empty( $changeset_data[ $nav_menu_item_setting_id ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $this->starter_content_settings_ids[] = $nav_menu_item_setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $this->pending_starter_content_settings_ids[] = $nav_menu_item_setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting_id = sprintf( 'nav_menu_locations[%s]', $nav_menu_location );
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->set_post_value( $setting_id, $nav_menu_term_id );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->starter_content_settings_ids[] = $setting_id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->pending_starter_content_settings_ids[] = $setting_id;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1102,7 +1102,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->set_post_value( $name, $value );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->starter_content_settings_ids[] = $name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->pending_starter_content_settings_ids[] = $name;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1114,11 +1114,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->set_post_value( $name, $value );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->starter_content_settings_ids[] = $name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->pending_starter_content_settings_ids[] = $name;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ! empty( $this->starter_content_settings_ids ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! empty( $this->pending_starter_content_settings_ids ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         if ( did_action( 'customize_register' ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->_save_starter_content_changeset();
</span><span class="cx" style="display: block; padding: 0 10px">                        } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1135,14 +1135,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function _save_starter_content_changeset() {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( empty( $this->starter_content_settings_ids ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( empty( $this->pending_starter_content_settings_ids ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->save_changeset_post( array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        'data' => array_fill_keys( $this->starter_content_settings_ids, array( 'starter_content' => true ) ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 'data' => array_fill_keys( $this->pending_starter_content_settings_ids, array( 'starter_content' => true ) ),
</ins><span class="cx" style="display: block; padding: 0 10px">                         'starter_content' => true,
</span><span class="cx" style="display: block; padding: 0 10px">                ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               $this->pending_starter_content_settings_ids = array();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span></span></pre></div>
<a id="trunksrcwpincludesthemephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/theme.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/theme.php   2016-11-17 04:20:22 UTC (rev 39275)
+++ trunk/src/wp-includes/theme.php     2016-11-17 08:17:57 UTC (rev 39276)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1824,7 +1824,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_theme_starter_content() {
</span><span class="cx" style="display: block; padding: 0 10px">        $theme_support = get_theme_support( 'starter-content' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( ! empty( $theme_support ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( is_array( $theme_support ) && ! empty( $theme_support[0] ) && is_array( $theme_support[0] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $config = $theme_support[0];
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                $config = array();
</span></span></pre></div>
<a id="trunktestsphpunittestscustomizemanagerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/customize/manager.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/customize/manager.php   2016-11-17 04:20:22 UTC (rev 39275)
+++ trunk/tests/phpunit/tests/customize/manager.php     2016-11-17 08:17:57 UTC (rev 39276)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -163,8 +163,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertInstanceOf( 'WPDieException', $exception );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertContains( 'Invalid changeset UUID', $exception->getMessage() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                update_option( 'fresh_site', 0 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $wp_customize = new WP_Customize_Manager();
</span><span class="cx" style="display: block; padding: 0 10px">                $wp_customize->setup_theme();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->assertFalse( has_action( 'after_setup_theme', array( $wp_customize, 'import_theme_starter_content' ) ) );
+
+               // Make sure that starter content import gets queued on a fresh site.
+               update_option( 'fresh_site', 1 );
+               $wp_customize->setup_theme();
+               $this->assertEquals( 100, has_action( 'after_setup_theme', array( $wp_customize, 'import_theme_starter_content' ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -299,6 +306,145 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Test WP_Customize_Manager::import_theme_starter_content().
+        *
+        * @covers WP_Customize_Manager::import_theme_starter_content()
+        * @covers WP_Customize_Manager::_save_starter_content_changeset()
+        */
+       function test_import_theme_starter_content() {
+               wp_set_current_user( self::$admin_user_id );
+
+               global $wp_customize;
+               $wp_customize = new WP_Customize_Manager();
+               $starter_content_config = array(
+                       'widgets' => array(
+                               'sidebar-1' => array(
+                                       'text_business_info',
+                                       'meta_custom' => array( 'meta', array(
+                                               'title' => 'Pre-hydrated meta widget.',
+                                       ) ),
+                               ),
+                       ),
+                       'nav_menus' => array(
+                               'top' => array(
+                                       'name'  => 'Menu Name',
+                                       'items' => array(
+                                               'page_home',
+                                               'page_about',
+                                               'page_blog',
+                                               'link_email',
+                                               'link_facebook',
+                                               'link_custom' => array(
+                                                       'title' => 'Custom',
+                                                       'url' => 'https://custom.example.com/',
+                                               ),
+                                       ),
+                               ),
+                       ),
+                       'posts' => array(
+                               'home',
+                               'about',
+                               'blog',
+                               'custom' => array(
+                                       'post_type' => 'post',
+                                       'post_title' => 'Custom',
+                               ),
+                       ),
+                       'options' => array(
+                               'blogname' => 'Starter Content Title',
+                               'blogdescription' => 'Starter Content Tagline',
+                               'show_on_front'  => 'page',
+                               'page_on_front'  => '{{home}}',
+                               'page_for_posts' => '{{blog}}',
+                       ),
+               );
+
+               add_theme_support( 'starter-content', $starter_content_config );
+               $this->assertEmpty( $wp_customize->unsanitized_post_values() );
+               $wp_customize->import_theme_starter_content();
+               $changeset_values = $wp_customize->unsanitized_post_values();
+               $expected_setting_ids = array(
+                       'blogname',
+                       'blogdescription',
+                       'widget_text[2]',
+                       'widget_meta[3]',
+                       'sidebars_widgets[sidebar-1]',
+                       'nav_menus_created_posts',
+                       'nav_menu[-1]',
+                       'nav_menu_item[-1]',
+                       'nav_menu_item[-2]',
+                       'nav_menu_item[-3]',
+                       'nav_menu_item[-4]',
+                       'nav_menu_item[-5]',
+                       'nav_menu_item[-6]',
+                       'nav_menu_locations[top]',
+                       'show_on_front',
+                       'page_on_front',
+                       'page_for_posts',
+               );
+               $this->assertEqualSets( $expected_setting_ids, array_keys( $changeset_values ) );
+
+               foreach ( array( 'widget_text[2]', 'widget_meta[3]' ) as $setting_id ) {
+                       $this->assertInternalType( 'array', $changeset_values[ $setting_id ] );
+                       $instance_data = $wp_customize->widgets->sanitize_widget_instance( $changeset_values[ $setting_id ] );
+                       $this->assertInternalType( 'array', $instance_data );
+                       $this->assertArrayHasKey( 'title', $instance_data );
+               }
+
+               $this->assertEquals( array( 'text-2', 'meta-3' ), $changeset_values['sidebars_widgets[sidebar-1]'] );
+
+               $posts_by_name = array();
+               foreach ( $changeset_values['nav_menus_created_posts'] as $post_id ) {
+                       $post = get_post( $post_id );
+                       $this->assertEquals( 'auto-draft', $post->post_status );
+                       $posts_by_name[ $post->post_name ] = $post->ID;
+               }
+
+               $this->assertEquals( 'page', $changeset_values['show_on_front'] );
+               $this->assertEquals( $posts_by_name['home'], $changeset_values['page_on_front'] );
+               $this->assertEquals( $posts_by_name['blog'], $changeset_values['page_for_posts'] );
+
+               $this->assertEquals( -1, $changeset_values['nav_menu_locations[top]'] );
+               $this->assertEquals( $posts_by_name['home'], $changeset_values['nav_menu_item[-1]']['object_id'] );
+
+               $this->assertEmpty( $wp_customize->changeset_data() );
+               $this->assertNull( $wp_customize->changeset_post_id() );
+               $this->assertEquals( 1000, has_action( 'customize_register', array( $wp_customize, '_save_starter_content_changeset' ) ) );
+               do_action( 'customize_register', $wp_customize ); // This will trigger the changeset save.
+               $this->assertInternalType( 'int', $wp_customize->changeset_post_id() );
+               $this->assertNotEmpty( $wp_customize->changeset_data() );
+               foreach ( $wp_customize->changeset_data() as $setting_id => $setting_params ) {
+                       $this->assertArrayHasKey( 'starter_content', $setting_params );
+                       $this->assertTrue( $setting_params['starter_content'] );
+               }
+
+               // Test that saving non-starter content on top of the changeset clears the starter_content flag.
+               $wp_customize->save_changeset_post( array(
+                       'data' => array(
+                               'blogname' => array( 'value' => 'Starter Content Modified' ),
+                       ),
+               ) );
+               $changeset_data = $wp_customize->changeset_data();
+               $this->assertArrayNotHasKey( 'starter_content', $changeset_data['blogname'] );
+               $this->assertArrayHasKey( 'starter_content', $changeset_data['blogdescription'] );
+
+               // Test that adding blogname starter content is ignored now that it is modified, but updating a non-modified starter content blog description passes.
+               $previous_blogname = $changeset_data['blogname']['value'];
+               $previous_blogdescription = $changeset_data['blogdescription']['value'];
+               $wp_customize->import_theme_starter_content( array(
+                       'options' => array(
+                               'blogname' => 'Newer Starter Content Title',
+                               'blogdescription' => 'Newer Starter Content Description',
+                       ),
+               ) );
+               $changeset_data = $wp_customize->changeset_data();
+               $this->assertEquals( $previous_blogname, $changeset_data['blogname']['value'] );
+               $this->assertArrayNotHasKey( 'starter_content', $changeset_data['blogname'] );
+               $this->assertNotEquals( $previous_blogdescription, $changeset_data['blogdescription']['value'] );
+               $this->assertArrayHasKey( 'starter_content', $changeset_data['blogdescription'] );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Test WP_Customize_Manager::customize_preview_init().
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 30937
</span></span></pre></div>
<a id="trunktestsphpunitteststhemegetThemeStarterContentphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/theme/getThemeStarterContent.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/theme/getThemeStarterContent.php                                (rev 0)
+++ trunk/tests/phpunit/tests/theme/getThemeStarterContent.php  2016-11-17 08:17:57 UTC (rev 39276)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,179 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * Tests get_theme_starter_content().
+ *
+ * @group themes
+ */
+class Tests_WP_Theme_Get_Theme_Starter_Content extends WP_UnitTestCase {
+
+       /**
+        * Testing passing an empty array as starter content.
+        */
+       function test_add_theme_support_empty() {
+               add_theme_support( 'starter-content', array() );
+               $starter_content = get_theme_starter_content();
+
+               $this->assertEmpty( $starter_content );
+       }
+
+       /**
+        * Testing passing nothing as starter content.
+        */
+       function test_add_theme_support_single_param() {
+               add_theme_support( 'starter-content' );
+               $starter_content = get_theme_starter_content();
+
+               $this->assertEmpty( $starter_content );
+       }
+
+       /**
+        * Testing that placeholder starter content gets expanded, that unrecognized placeholders are discarded, and that custom items are recognized.
+        */
+       function test_default_content_sections() {
+               /*
+                * All placeholder identifiers should be referenced in this sample starter
+                * content and then tested to ensure they get hydrated in the call to
+                * get_theme_starter_content() to ensure that the starter content
+                * placeholder identifiers remain intact in core.
+                */
+               $dehydrated_starter_content = array(
+                       'widgets' => array(
+                               'sidebar-1' => array(
+                                       'text_business_info',
+                                       'text_about',
+                                       'archives',
+                                       'calendar',
+                                       'categories',
+                                       'meta',
+                                       'recent-comments',
+                                       'recent-posts',
+                                       'search',
+                                       'unknown',
+                                       'meta_custom' => array( 'meta', array(
+                                               'title' => 'Pre-hydrated meta widget.',
+                                       ) ),
+                               ),
+                       ),
+                       'nav_menus' => array(
+                               'top' => array(
+                                       'name' => 'Menu Name',
+                                       'items' => array(
+                                               'page_home',
+                                               'page_about',
+                                               'page_blog',
+                                               'page_news',
+                                               'page_contact',
+                                               'link_email',
+                                               'link_facebook',
+                                               'link_foursquare',
+                                               'link_github',
+                                               'link_instagram',
+                                               'link_linkedin',
+                                               'link_pinterest',
+                                               'link_twitter',
+                                               'link_yelp',
+                                               'link_youtube',
+                                               'link_unknown',
+                                               'link_custom' => array(
+                                                       'title' => 'Custom',
+                                                       'url' => 'https://custom.example.com/',
+                                               ),
+                                       ),
+                               ),
+                       ),
+                       'posts' => array(
+                               'home',
+                               'about',
+                               'contact',
+                               'blog',
+                               'news',
+                               'homepage-section',
+                               'unknown',
+                               'custom' => array(
+                                       'post_type' => 'post',
+                                       'post_title' => 'Custom',
+                               ),
+                       ),
+                       'options' => array(
+                               'show_on_front' => 'page',
+                               'page_on_front' => '{{home}}',
+                               'page_for_posts' => '{{blog}}',
+                       ),
+                       'theme_mods' => array(
+                               'panel_1' => '{{homepage-section}}',
+                               'panel_2' => '{{about}}',
+                               'panel_3' => '{{blog}}',
+                               'panel_4' => '{{contact}}',
+                       ),
+               );
+
+               add_theme_support( 'starter-content', $dehydrated_starter_content );
+
+               $hydrated_starter_content = get_theme_starter_content();
+               $this->assertSame( $hydrated_starter_content['theme_mods'], $dehydrated_starter_content['theme_mods'] );
+               $this->assertSame( $hydrated_starter_content['options'], $dehydrated_starter_content['options'] );
+               $this->assertCount( 16, $hydrated_starter_content['nav_menus']['top']['items'], 'Unknown should be dropped, custom should be present.' );
+               $this->assertCount( 10, $hydrated_starter_content['widgets']['sidebar-1'], 'Unknown should be dropped.' );
+
+               foreach ( $hydrated_starter_content['widgets']['sidebar-1'] as $widget ) {
+                       $this->assertInternalType( 'array', $widget );
+                       $this->assertCount( 2, $widget );
+                       $this->assertInternalType( 'string', $widget[0] );
+                       $this->assertInternalType( 'array', $widget[1] );
+                       $this->assertArrayHasKey( 'title', $widget[1] );
+               }
+
+               foreach ( $hydrated_starter_content['nav_menus']['top']['items'] as $nav_menu_item ) {
+                       $this->assertInternalType( 'array', $nav_menu_item );
+                       $this->assertTrue( ! empty( $nav_menu_item['object_id'] ) || ! empty( $nav_menu_item['url'] ) );
+               }
+
+               foreach ( $hydrated_starter_content['posts'] as $key => $post ) {
+                       $this->assertInternalType( 'string', $key );
+                       $this->assertFalse( is_numeric( $key ) );
+                       $this->assertInternalType( 'array', $post );
+                       $this->assertArrayHasKey( 'post_type', $post );
+                       $this->assertArrayHasKey( 'post_title', $post );
+               }
+       }
+
+       /**
+        * Testing the filter with the text_credits widget.
+        */
+       function test_get_theme_starter_content_filter() {
+
+               add_theme_support( 'starter-content',
+                       array(
+                               'widgets' => array(
+                                       'sidebar-1' => array(
+                                               'text_about',
+                                       ),
+                               ),
+                       )
+               );
+
+               add_filter( 'get_theme_starter_content', array( $this, 'filter_theme_starter_content' ), 10, 2 );
+               $starter_content = get_theme_starter_content();
+
+               $this->assertCount( 2, $starter_content['widgets']['sidebar-1'] );
+               $this->assertEquals( 'Filtered Widget', $starter_content['widgets']['sidebar-1'][1][1]['title'] );
+       }
+
+       /**
+        * Filter the append a widget starter content.
+        *
+        * @param array $content Starter content (hydrated).
+        * @param array $config  Starter content config (pre-hydrated).
+        * @return array Filtered starter content.
+        */
+       public function filter_theme_starter_content( $content, $config ) {
+               $this->assertInternalType( 'array', $config );
+               $this->assertCount( 1, $config['widgets']['sidebar-1'] );
+               $content['widgets']['sidebar-1'][] = array( 'text', array(
+                       'title' => 'Filtered Widget',
+                       'text'  => 'Custom ',
+               ) );
+               return $content;
+       }
+}
</ins></span></pre>
</div>
</div>

</body>
</html>