Tests_WP_Customize_Manager   D
last analyzed

Complexity

Total Complexity 123

Size/Duplication

Total Lines 2763
Duplicated Lines 3.73 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 103
loc 2763
rs 4.4102
c 0
b 0
f 0
wmc 123
lcom 1
cbo 6

85 Methods

Rating   Name   Duplication   Size   Complexity  
A wpSetUpBeforeClass() 0 5 1
A setUp() 0 7 1
A tearDown() 0 7 1
A get_inactive_core_theme() 0 10 4
A instantiate() 0 5 1
B test_constructor() 0 30 1
B test_setup_theme_in_customize_admin() 0 40 3
B test_setup_theme_in_frontend() 0 29 2
A test_changeset_uuid() 0 6 1
A test_wp_loaded() 0 12 1
A test_find_changeset_post_id() 0 16 1
A test_changeset_post_id() 0 18 1
A test_changeset_data() 0 19 1
B test_import_theme_starter_content() 0 240 6
B test_customize_preview_init() 0 38 2
A test_filter_iframe_security_headers() 0 9 1
A test_add_state_query_params() 0 53 1
B test_save_changeset_post_without_theme_activation() 0 232 4
A filter_customize_changeset_save_data() 0 14 1
A return_illegal_error() 0 4 1
B test_save_changeset_post_with_theme_activation() 0 32 1
B test_save_changeset_post_with_varying_users() 8 120 4
B create_test_manager() 0 27 1
B test_save_changeset_post_with_unchanged_values() 0 84 1
A test_save_changeset_post_with_varying_unfiltered_html_cap() 0 60 1
A register_scratchpad_setting() 0 10 1
A filter_sanitize_scratchpad() 0 4 1
A filter_customize_setting_to_log_current_user() 0 5 1
A test_is_cross_domain() 0 12 1
A test_get_allowed_urls() 0 12 1
A filter_customize_allowed_urls() 0 5 1
A test_doing_ajax() 0 13 2
A test_not_doing_ajax() 0 9 3
A test_unsanitized_post_values_from_input() 0 23 1
B test_unsanitized_post_values_with_changeset_and_stashed_theme_mods() 0 102 1
A test_post_value() 0 19 1
B test_invalid_post_value() 0 31 1
A filter_customize_sanitize_foo() 0 12 4
A filter_customize_validate_foo() 0 7 2
A test_post_value_validation_sanitization_order() 0 18 1
A filter_customize_sanitize_numeric() 0 4 1
A filter_customize_validate_numeric() 0 7 3
B test_validate_setting_values() 0 42 1
A test_late_validate_setting_values() 0 20 1
B test_validate_setting_values_args() 0 28 1
A late_validate_length() 0 8 2
A test_validate_setting_values_validation_sanitization_order() 0 15 1
A test_prepare_setting_validity_for_js() 0 19 2
B test_set_post_value() 0 26 1
A sanitize_foo_for_test_set_post_value() 0 4 1
A capture_customize_post_value_set_actions() 0 6 1
A test_add_dynamic_settings() 0 15 1
A test_has_published_pages() 0 13 2
A test_has_published_pages_when_nav_menus_created_posts() 0 17 2
A test_register_dynamic_settings() 0 19 1
A action_customize_register_for_dynamic_settings() 0 5 1
A filter_customize_dynamic_setting_args_for_test_dynamic_settings() 0 8 2
A filter_customize_dynamic_setting_class_for_test_dynamic_settings() 0 7 1
A test_is_ios() 0 4 1
A test_get_document_title_template() 0 5 1
A test_preview_url() 0 9 1
B test_return_url() 0 32 1
A test_autofocus() 0 23 1
A test_nonces() 0 12 1
A filter_customize_refresh_nonces() 0 6 1
B test_customize_pane_settings() 0 29 1
A test_remove_frameless_preview_messenger_channel() 0 15 1
B test_customize_preview_settings() 0 29 1
B test_customize_loaded_components_filter() 0 24 1
A return_array_containing_widgets() 8 9 1
A return_array_containing_nav_menus() 8 9 1
B test_prepare_controls_stable_sorting() 0 34 2
B test_add_section_return_instance() 23 28 1
A test_add_setting_return_instance() 0 18 1
A test_add_setting_honoring_dynamic() 0 17 1
A return_dynamic_customize_setting_class() 0 8 2
A return_dynamic_customize_setting_args() 0 7 2
B test_add_panel_return_instance() 22 27 1
B test_add_control_return_instance() 0 38 1
B test_get_previewable_devices() 0 32 1
A filtered_device_list() 0 9 1
A filter_customize_previewable_devices() 0 4 1
B test_prepare_controls_wp_list_sort_controls() 0 24 2
A test_prepare_controls_wp_list_sort_sections() 17 20 2
A test_prepare_controls_wp_list_sort_panels() 17 20 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Tests_WP_Customize_Manager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Tests_WP_Customize_Manager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * WP_Customize_Manager tests.
4
 *
5
 * @package WordPress
6
 */
7
8
/**
9
 * Tests for the WP_Customize_Manager class.
10
 *
11
 * @group customize
12
 */
13
class Tests_WP_Customize_Manager extends WP_UnitTestCase
14
{
15
16
    /**
17
     * Customize manager instance re-instantiated with each test.
18
     *
19
     * @var WP_Customize_Manager
20
     */
21
    public $manager;
22
23
    /**
24
     * Symbol.
25
     *
26
     * @var stdClass
27
     */
28
    public $undefined;
29
30
    /**
31
     * Admin user ID.
32
     *
33
     * @var int
34
     */
35
    protected static $admin_user_id;
36
37
    /**
38
     * Subscriber user ID.
39
     *
40
     * @var int
41
     */
42
    protected static $subscriber_user_id;
43
44
    /**
45
     * Set up before class.
46
     *
47
     * @param WP_UnitTest_Factory $factory Factory.
48
     */
49
    public static function wpSetUpBeforeClass( $factory ) 
0 ignored issues
show
Coding Style introduced by
The function name wpSetUpBeforeClass is in camel caps, but expected wp_set_up_before_class instead as per the coding standard.
Loading history...
50
    {
51
        self::$subscriber_user_id = $factory->user->create(array( 'role' => 'subscriber' ));
52
        self::$admin_user_id = $factory->user->create(array( 'role' => 'administrator' ));
53
    }
54
55
    /**
56
     * Set up test.
57
     */
58
    function setUp() 
0 ignored issues
show
Coding Style introduced by
The function name setUp is in camel caps, but expected set_up instead as per the coding standard.
Loading history...
59
    {
60
        parent::setUp();
61
        include_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
62
        $this->manager = $this->instantiate();
63
        $this->undefined = new stdClass();
64
    }
65
66
    /**
67
     * Tear down test.
68
     */
69
    function tearDown() 
0 ignored issues
show
Coding Style introduced by
The function name tearDown is in camel caps, but expected tear_down instead as per the coding standard.
Loading history...
70
    {
71
        $this->manager = null;
72
        unset($GLOBALS['wp_customize']);
73
        $_REQUEST = array();
74
        parent::tearDown();
75
    }
76
77
    /**
78
     * Get a core theme that is not the same as the current theme.
79
     *
80
     * @throws Exception If an inactive core Twenty* theme cannot be found.
81
     * @return string Theme slug (stylesheet).
82
     */
83
    function get_inactive_core_theme() 
84
    {
85
        $stylesheet = get_stylesheet();
86
        foreach ( wp_get_themes() as $theme ) {
87
            if ($theme->stylesheet !== $stylesheet && 0 === strpos($theme->stylesheet, 'twenty') ) {
88
                return $theme->stylesheet;
89
            }
90
        }
91
        throw new Exception('Unable to find inactive twenty* theme.');
92
    }
93
94
    /**
95
     * Instantiate class, set global $wp_customize, and return instance.
96
     *
97
     * @return WP_Customize_Manager
98
     */
99
    function instantiate() 
100
    {
101
        $GLOBALS['wp_customize'] = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
102
        return $GLOBALS['wp_customize'];
103
    }
104
105
    /**
106
     * Test WP_Customize_Manager::__construct().
107
     *
108
     * @covers WP_Customize_Manager::__construct()
109
     */
110
    function test_constructor() 
111
    {
112
        $uuid = wp_generate_uuid4();
113
        $theme = 'twentyfifteen';
114
        $messenger_channel = 'preview-123';
115
        $wp_customize = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
116
            array(
117
            'changeset_uuid' => $uuid,
118
            'theme' => $theme,
119
            'messenger_channel' => $messenger_channel,
120
            ) 
121
        );
122
        $this->assertEquals($uuid, $wp_customize->changeset_uuid());
123
        $this->assertEquals($theme, $wp_customize->get_stylesheet());
124
        $this->assertEquals($messenger_channel, $wp_customize->get_messenger_channel());
125
126
        $theme = 'twentyfourteen';
127
        $messenger_channel = 'preview-456';
128
        $_REQUEST['theme'] = $theme;
129
        $_REQUEST['customize_messenger_channel'] = $messenger_channel;
130
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
131
        $this->assertEquals($theme, $wp_customize->get_stylesheet());
132
        $this->assertEquals($messenger_channel, $wp_customize->get_messenger_channel());
133
134
        $theme = 'twentyfourteen';
135
        $_REQUEST['customize_theme'] = $theme;
136
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
137
        $this->assertEquals($theme, $wp_customize->get_stylesheet());
138
        $this->assertNotEmpty($wp_customize->changeset_uuid());
139
    }
140
141
    /**
142
     * Test WP_Customize_Manager::setup_theme() for admin screen.
143
     *
144
     * @covers WP_Customize_Manager::setup_theme()
145
     */
146
    function test_setup_theme_in_customize_admin() 
147
    {
148
        global $pagenow, $wp_customize;
149
        $pagenow = 'customize.php';
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
150
        set_current_screen('customize');
151
152
        // Unauthorized.
153
        $exception = null;
154
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
155
        wp_set_current_user(self::$subscriber_user_id);
156
        try {
157
            $wp_customize->setup_theme();
158
        } catch ( Exception $e ) {
159
            $exception = $e;
160
        }
161
        $this->assertInstanceOf('WPDieException', $exception);
162
        $this->assertContains('you are not allowed to customize this site', $exception->getMessage());
163
164
        // Bad changeset.
165
        $exception = null;
166
        wp_set_current_user(self::$admin_user_id);
167
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => 'bad' ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
168
        try {
169
            $wp_customize->setup_theme();
170
        } catch ( Exception $e ) {
171
            $exception = $e;
172
        }
173
        $this->assertInstanceOf('WPDieException', $exception);
174
        $this->assertContains('Invalid changeset UUID', $exception->getMessage());
175
176
        update_option('fresh_site', 0);
177
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
178
        $wp_customize->setup_theme();
179
        $this->assertFalse(has_action('after_setup_theme', array( $wp_customize, 'import_theme_starter_content' )));
180
181
        // Make sure that starter content import gets queued on a fresh site.
182
        update_option('fresh_site', 1);
183
        $wp_customize->setup_theme();
184
        $this->assertEquals(100, has_action('after_setup_theme', array( $wp_customize, 'import_theme_starter_content' )));
185
    }
186
187
    /**
188
     * Test WP_Customize_Manager::setup_theme() for frontend.
189
     *
190
     * @covers WP_Customize_Manager::setup_theme()
191
     */
192
    function test_setup_theme_in_frontend() 
193
    {
194
        global $wp_customize, $pagenow, $show_admin_bar;
195
        $pagenow = 'front';
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
196
        set_current_screen('front');
197
198
        wp_set_current_user(0);
199
        $exception = null;
200
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
201
        wp_set_current_user(self::$subscriber_user_id);
202
        try {
203
            $wp_customize->setup_theme();
204
        } catch ( Exception $e ) {
205
            $exception = $e;
206
        }
207
        $this->assertInstanceOf('WPDieException', $exception);
208
        $this->assertContains('Non-existent changeset UUID', $exception->getMessage());
209
210
        wp_set_current_user(self::$admin_user_id);
211
        $wp_customize = new WP_Customize_Manager(array( 'messenger_channel' => 'preview-1' ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
212
        $wp_customize->setup_theme();
213
        $this->assertFalse($show_admin_bar);
214
215
        show_admin_bar(true);
0 ignored issues
show
introduced by
Removal of admin bar is prohibited.
Loading history...
216
        wp_set_current_user(self::$admin_user_id);
217
        $wp_customize = new WP_Customize_Manager(array( 'messenger_channel' => null ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
218
        $wp_customize->setup_theme();
219
        $this->assertTrue($show_admin_bar);
220
    }
221
222
    /**
223
     * Test WP_Customize_Manager::changeset_uuid().
224
     *
225
     * @ticket 30937
226
     * @covers WP_Customize_Manager::changeset_uuid()
227
     */
228
    function test_changeset_uuid() 
229
    {
230
        $uuid = wp_generate_uuid4();
231
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
232
        $this->assertEquals($uuid, $wp_customize->changeset_uuid());
233
    }
234
235
    /**
236
     * Test WP_Customize_Manager::wp_loaded().
237
     *
238
     * Ensure that post values are previewed even without being in preview.
239
     *
240
     * @ticket 30937
241
     * @covers WP_Customize_Manager::wp_loaded()
242
     */
243
    function test_wp_loaded() 
244
    {
245
        wp_set_current_user(self::$admin_user_id);
246
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
247
        $title = 'Hello World';
248
        $wp_customize->set_post_value('blogname', $title);
249
        $this->assertNotEquals($title, get_option('blogname'));
250
        $wp_customize->wp_loaded();
251
        $this->assertFalse($wp_customize->is_preview());
252
        $this->assertEquals($title, $wp_customize->get_setting('blogname')->value());
253
        $this->assertEquals($title, get_option('blogname'));
254
    }
255
256
    /**
257
     * Test WP_Customize_Manager::find_changeset_post_id().
258
     *
259
     * @ticket 30937
260
     * @covers WP_Customize_Manager::find_changeset_post_id()
261
     */
262
    function test_find_changeset_post_id() 
263
    {
264
        $uuid = wp_generate_uuid4();
265
        $post_id = $this->factory()->post->create(
266
            array(
267
            'post_name' => $uuid,
268
            'post_type' => 'customize_changeset',
269
            'post_status' => 'auto-draft',
270
            'post_content' => '{}',
271
            ) 
272
        );
273
274
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
275
        $this->assertNull($wp_customize->find_changeset_post_id(wp_generate_uuid4()));
276
        $this->assertEquals($post_id, $wp_customize->find_changeset_post_id($uuid));
277
    }
278
279
    /**
280
     * Test WP_Customize_Manager::changeset_post_id().
281
     *
282
     * @ticket 30937
283
     * @covers WP_Customize_Manager::changeset_post_id()
284
     */
285
    function test_changeset_post_id() 
286
    {
287
        $uuid = wp_generate_uuid4();
288
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
289
        $this->assertNull($wp_customize->changeset_post_id());
290
291
        $uuid = wp_generate_uuid4();
292
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
293
        $post_id = $this->factory()->post->create(
294
            array(
295
            'post_name' => $uuid,
296
            'post_type' => 'customize_changeset',
297
            'post_status' => 'auto-draft',
298
            'post_content' => '{}',
299
            ) 
300
        );
301
        $this->assertEquals($post_id, $wp_customize->changeset_post_id());
302
    }
303
304
    /**
305
     * Test WP_Customize_Manager::changeset_data().
306
     *
307
     * @ticket 30937
308
     * @covers WP_Customize_Manager::changeset_data()
309
     */
310
    function test_changeset_data() 
311
    {
312
        $uuid = wp_generate_uuid4();
313
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
314
        $this->assertEquals(array(), $wp_customize->changeset_data());
315
316
        $uuid = wp_generate_uuid4();
317
        $data = array( 'blogname' => array( 'value' => 'Hello World' ) );
318
        $this->factory()->post->create(
319
            array(
320
            'post_name' => $uuid,
321
            'post_type' => 'customize_changeset',
322
            'post_status' => 'auto-draft',
323
            'post_content' => wp_json_encode($data),
324
            ) 
325
        );
326
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
327
        $this->assertEquals($data, $wp_customize->changeset_data());
328
    }
329
330
    /**
331
     * Test WP_Customize_Manager::import_theme_starter_content().
332
     *
333
     * @covers WP_Customize_Manager::import_theme_starter_content()
334
     * @covers WP_Customize_Manager::_save_starter_content_changeset()
335
     */
336
    function test_import_theme_starter_content() 
337
    {
338
        wp_set_current_user(self::$admin_user_id);
339
        register_nav_menu('top', 'Top');
340
        add_theme_support('custom-logo');
341
        add_theme_support('custom-header');
342
        add_theme_support('custom-background');
343
344
        $canola_file = DIR_TESTDATA . '/images/canola.jpg';
345
        $existing_canola_attachment_id = self::factory()->attachment->create_object(
346
            $canola_file, 0, array(
0 ignored issues
show
Documentation introduced by
$canola_file is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
347
            'post_mime_type' => 'image/jpeg',
348
            'post_type' => 'attachment',
349
            'post_name' => 'canola',
350
            ) 
351
        );
352
        $existing_published_home_page_id = $this->factory()->post->create(
353
            array(
354
            'post_name' => 'home',
355
            'post_type' => 'page',
356
            'post_status' => 'publish'
357
            ) 
358
        );
359
        $existing_auto_draft_about_page_id = $this->factory()->post->create(
360
            array(
361
            'post_name' => 'about',
362
            'post_type' => 'page',
363
            'post_status' => 'auto-draft'
364
            ) 
365
        );
366
367
        global $wp_customize;
368
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
369
        $starter_content_config = array(
370
         'widgets' => array(
371
          'sidebar-1' => array(
372
        'text_business_info',
373
        'meta_custom' => array( 'meta', array(
374
         'title' => 'Pre-hydrated meta widget.',
375
        ) ),
376
          ),
377
         ),
378
         'nav_menus' => array(
379
          'top' => array(
380
        'name'  => 'Menu Name',
381
        'items' => array(
382
         'page_home',
383
         'page_about',
384
         'page_blog',
385
         'link_email',
386
         'link_facebook',
387
         'link_custom' => array(
388
          'title' => 'Custom',
389
          'url' => 'https://custom.example.com/',
390
         ),
391
           ),
392
          ),
393
         ),
394
         'posts' => array(
395
          'home',
396
          'about' => array(
397
        'template' => 'sample-page-template.php',
398
          ),
399
          'blog',
400
          'custom' => array(
401
           'post_type' => 'post',
402
           'post_title' => 'Custom',
403
           'thumbnail' => '{{waffles}}',
404
          ),
405
         ),
406
         'attachments' => array(
407
          'waffles' => array(
408
        'post_title' => 'Waffles',
409
        'post_content' => 'Waffles Attachment Description',
410
        'post_excerpt' => 'Waffles Attachment Caption',
411
        'file' => DIR_TESTDATA . '/images/waffles.jpg',
412
          ),
413
          'canola' => array(
414
           'post_title' => 'Canola',
415
           'post_content' => 'Canola Attachment Description',
416
           'post_excerpt' => 'Canola Attachment Caption',
417
           'file' => DIR_TESTDATA . '/images/canola.jpg',
418
          ),
419
         ),
420
         'options' => array(
421
          'blogname' => 'Starter Content Title',
422
          'blogdescription' => 'Starter Content Tagline',
423
          'show_on_front'  => 'page',
424
          'page_on_front'  => '{{home}}',
425
          'page_for_posts' => '{{blog}}',
426
         ),
427
         'theme_mods' => array(
428
          'custom_logo' => '{{canola}}',
429
          'header_image' => '{{waffles}}',
430
          'background_image' => '{{waffles}}',
431
         ),
432
        );
433
434
        update_option('posts_per_page', 1); // To check #39022.
435
        add_theme_support('starter-content', $starter_content_config);
436
        $this->assertEmpty($wp_customize->unsanitized_post_values());
437
        $wp_customize->import_theme_starter_content();
438
        $changeset_values = $wp_customize->unsanitized_post_values();
439
        $expected_setting_ids = array(
440
         'blogname',
441
         'blogdescription',
442
         'custom_logo',
443
         'header_image_data',
444
         'background_image',
445
         'widget_text[2]',
446
         'widget_meta[3]',
447
         'sidebars_widgets[sidebar-1]',
448
         'nav_menus_created_posts',
449
         'nav_menu[-1]',
450
         'nav_menu_item[-1]',
451
         'nav_menu_item[-2]',
452
         'nav_menu_item[-3]',
453
         'nav_menu_item[-4]',
454
         'nav_menu_item[-5]',
455
         'nav_menu_item[-6]',
456
         'nav_menu_locations[top]',
457
         'show_on_front',
458
         'page_on_front',
459
         'page_for_posts',
460
        );
461
        $this->assertEqualSets($expected_setting_ids, array_keys($changeset_values));
462
463
        foreach ( array( 'widget_text[2]', 'widget_meta[3]' ) as $setting_id ) {
464
               $this->assertInternalType('array', $changeset_values[ $setting_id ]);
465
               $instance_data = $wp_customize->widgets->sanitize_widget_instance($changeset_values[ $setting_id ]);
466
               $this->assertInternalType('array', $instance_data);
467
               $this->assertArrayHasKey('title', $instance_data);
468
        }
469
470
        $this->assertEquals(array( 'text-2', 'meta-3' ), $changeset_values['sidebars_widgets[sidebar-1]']);
471
472
        $posts_by_name = array();
473
        $this->assertCount(6, $changeset_values['nav_menus_created_posts']);
474
        $this->assertContains($existing_published_home_page_id, $changeset_values['nav_menus_created_posts'], 'Expected reuse of non-auto-draft posts.');
475
        $this->assertContains($existing_canola_attachment_id, $changeset_values['nav_menus_created_posts'], 'Expected reuse of non-auto-draft attachment.');
476
        $this->assertNotContains($existing_auto_draft_about_page_id, $changeset_values['nav_menus_created_posts'], 'Expected non-reuse of auto-draft posts.');
477
        foreach ( $changeset_values['nav_menus_created_posts'] as $post_id ) {
478
             $post = get_post($post_id);
479
            if ($post->ID === $existing_published_home_page_id ) {
480
                $this->assertEquals('publish', $post->post_status);
481
            } elseif ($post->ID === $existing_canola_attachment_id ) {
482
                $this->assertEquals('inherit', $post->post_status);
483
            } else {
484
                $this->assertEquals('auto-draft', $post->post_status);
485
            }
486
                $posts_by_name[ $post->post_name ] = $post->ID;
487
        }
488
        $this->assertEquals(array( 'waffles', 'canola', 'home', 'about', 'blog', 'custom' ), array_keys($posts_by_name));
489
        $this->assertEquals('Custom', get_post($posts_by_name['custom'])->post_title);
490
        $this->assertEquals('sample-page-template.php', get_page_template_slug($posts_by_name['about']));
491
        $this->assertEquals('', get_page_template_slug($posts_by_name['blog']));
492
        $this->assertEquals($posts_by_name['waffles'], get_post_thumbnail_id($posts_by_name['custom']));
493
        $this->assertEquals('', get_post_thumbnail_id($posts_by_name['blog']));
494
        $attachment_metadata = wp_get_attachment_metadata($posts_by_name['waffles']);
495
        $this->assertEquals('Waffles', get_post($posts_by_name['waffles'])->post_title);
496
        $this->assertArrayHasKey('file', $attachment_metadata);
497
        $this->assertContains('waffles', $attachment_metadata['file']);
498
499
        $this->assertEquals('page', $changeset_values['show_on_front']);
500
        $this->assertEquals($posts_by_name['home'], $changeset_values['page_on_front']);
501
        $this->assertEquals($posts_by_name['blog'], $changeset_values['page_for_posts']);
502
503
        $this->assertEquals(-1, $changeset_values['nav_menu_locations[top]']);
504
        $this->assertEquals($posts_by_name['home'], $changeset_values['nav_menu_item[-1]']['object_id']);
505
506
        $this->assertEmpty($wp_customize->changeset_data());
507
        $this->assertNull($wp_customize->changeset_post_id());
508
        $this->assertEquals(1000, has_action('customize_register', array( $wp_customize, '_save_starter_content_changeset' )));
509
        do_action('customize_register', $wp_customize); // This will trigger the changeset save.
510
        $this->assertInternalType('int', $wp_customize->changeset_post_id());
511
        $this->assertNotEmpty($wp_customize->changeset_data());
512
        foreach ( $wp_customize->changeset_data() as $setting_id => $setting_params ) {
513
             $this->assertArrayHasKey('starter_content', $setting_params);
514
             $this->assertTrue($setting_params['starter_content']);
515
        }
516
517
        // Ensure that re-importing doesn't cause auto-drafts to balloon.
518
        $wp_customize->import_theme_starter_content();
519
        $changeset_data = $wp_customize->changeset_data();
520
        $this->assertEqualSets(array_values($posts_by_name), $changeset_data['nav_menus_created_posts']['value'], 'Auto-drafts should not get re-created and amended with each import.');
521
522
        // Test that saving non-starter content on top of the changeset clears the starter_content flag.
523
        $wp_customize->save_changeset_post(
524
            array(
525
            'data' => array(
526
            'blogname' => array( 'value' => 'Starter Content Modified' ),
527
            ),
528
            ) 
529
        );
530
        $changeset_data = $wp_customize->changeset_data();
531
        $this->assertArrayNotHasKey('starter_content', $changeset_data['blogname']);
532
        $this->assertArrayHasKey('starter_content', $changeset_data['blogdescription']);
533
534
        // Test that adding blogname starter content is ignored now that it is modified, but updating a non-modified starter content blog description passes.
535
        $previous_blogname = $changeset_data['blogname']['value'];
536
        $previous_blogdescription = $changeset_data['blogdescription']['value'];
537
        $wp_customize->import_theme_starter_content(
538
            array(
539
            'options' => array(
540
            'blogname' => 'Newer Starter Content Title',
541
            'blogdescription' => 'Newer Starter Content Description',
542
            ),
543
            ) 
544
        );
545
        $changeset_data = $wp_customize->changeset_data();
546
        $this->assertEquals($previous_blogname, $changeset_data['blogname']['value']);
547
        $this->assertArrayNotHasKey('starter_content', $changeset_data['blogname']);
548
        $this->assertNotEquals($previous_blogdescription, $changeset_data['blogdescription']['value']);
549
        $this->assertArrayHasKey('starter_content', $changeset_data['blogdescription']);
550
551
        // Publish.
552
        $this->assertEmpty(get_custom_logo());
553
        $this->assertEmpty(get_header_image());
554
        $this->assertEmpty(get_background_image());
555
        $this->assertEmpty(get_theme_mod('custom_logo'));
556
        $this->assertEmpty(get_theme_mod('header_image'));
557
        $this->assertEmpty(get_theme_mod('background_image'));
558
        $this->assertEquals('auto-draft', get_post($posts_by_name['about'])->post_status);
559
        $this->assertEquals('auto-draft', get_post($posts_by_name['waffles'])->post_status);
560
        $this->assertNotEquals($changeset_data['blogname']['value'], get_option('blogname'));
561
        $r = $wp_customize->save_changeset_post(array( 'status' => 'publish' ));
562
        $this->assertInternalType('array', $r);
563
        $this->assertEquals('publish', get_post($posts_by_name['about'])->post_status);
564
        $this->assertEquals('inherit', get_post($posts_by_name['waffles'])->post_status);
565
        $this->assertEquals($changeset_data['blogname']['value'], get_option('blogname'));
566
        $this->assertNotEmpty(get_theme_mod('custom_logo'));
567
        $this->assertNotEmpty(get_theme_mod('header_image'));
568
        $this->assertNotEmpty(get_theme_mod('background_image'));
569
        $this->assertNotEmpty(get_custom_logo());
570
        $this->assertNotEmpty(get_header_image());
571
        $this->assertNotEmpty(get_background_image());
572
        $this->assertContains('canola', get_custom_logo());
573
        $this->assertContains('waffles', get_header_image());
574
        $this->assertContains('waffles', get_background_image());
575
    }
576
577
    /**
578
     * Test WP_Customize_Manager::customize_preview_init().
579
     *
580
     * @ticket 30937
581
     * @covers WP_Customize_Manager::customize_preview_init()
582
     */
583
    function test_customize_preview_init() 
584
    {
585
586
        // Test authorized admin user.
587
        wp_set_current_user(self::$admin_user_id);
588
        $did_action_customize_preview_init = did_action('customize_preview_init');
589
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
590
        $wp_customize->customize_preview_init();
591
        $this->assertEquals($did_action_customize_preview_init + 1, did_action('customize_preview_init'));
592
593
        $this->assertEquals(10, has_action('wp_head', 'wp_no_robots'));
594
        $this->assertEquals(10, has_action('wp_head', array( $wp_customize, 'remove_frameless_preview_messenger_channel' )));
595
        $this->assertEquals(10, has_filter('wp_headers', array( $wp_customize, 'filter_iframe_security_headers' )));
596
        $this->assertEquals(10, has_filter('wp_redirect', array( $wp_customize, 'add_state_query_params' )));
597
        $this->assertTrue(wp_script_is('customize-preview', 'enqueued'));
598
        $this->assertEquals(10, has_action('wp_head', array( $wp_customize, 'customize_preview_loading_style' )));
599
        $this->assertEquals(20, has_action('wp_footer', array( $wp_customize, 'customize_preview_settings' )));
600
601
        // Test unauthorized user outside preview (no messenger_channel).
602
        wp_set_current_user(self::$subscriber_user_id);
603
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
604
        $wp_customize->register_controls();
605
        $this->assertNotEmpty($wp_customize->controls());
606
        $wp_customize->customize_preview_init();
607
        $this->assertEmpty($wp_customize->controls());
608
609
        // Test unauthorized user inside preview (with messenger_channel).
610
        wp_set_current_user(self::$subscriber_user_id);
611
        $wp_customize = new WP_Customize_Manager(array( 'messenger_channel' => 'preview-0' ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
612
        $exception = null;
613
        try {
614
            $wp_customize->customize_preview_init();
615
        } catch ( WPDieException $e ) {
616
            $exception = $e;
617
        }
618
        $this->assertNotNull($exception);
619
        $this->assertContains('Unauthorized', $exception->getMessage());
620
    }
621
622
    /**
623
     * Test WP_Customize_Manager::filter_iframe_security_headers().
624
     *
625
     * @ticket 30937
626
     * @covers WP_Customize_Manager::filter_iframe_security_headers()
627
     */
628
    function test_filter_iframe_security_headers() 
629
    {
630
        $customize_url = admin_url('customize.php');
631
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
632
        $headers = $wp_customize->filter_iframe_security_headers(array());
633
        $this->assertArrayHasKey('X-Frame-Options', $headers);
634
        $this->assertArrayHasKey('Content-Security-Policy', $headers);
635
        $this->assertEquals("ALLOW-FROM $customize_url", $headers['X-Frame-Options']);
636
    }
637
638
    /**
639
     * Test WP_Customize_Manager::add_state_query_params().
640
     *
641
     * @ticket 30937
642
     * @covers WP_Customize_Manager::add_state_query_params()
643
     */
644
    function test_add_state_query_params() 
645
    {
646
        $preview_theme = $this->get_inactive_core_theme();
647
648
        $uuid = wp_generate_uuid4();
649
        $messenger_channel = 'preview-0';
650
        $wp_customize = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
651
            array(
652
            'changeset_uuid' => $uuid,
653
            'messenger_channel' => $messenger_channel,
654
            ) 
655
        );
656
        $url = $wp_customize->add_state_query_params(home_url('/'));
657
        $parsed_url = wp_parse_url($url);
658
        parse_str($parsed_url['query'], $query_params);
659
        $this->assertArrayHasKey('customize_messenger_channel', $query_params);
660
        $this->assertArrayHasKey('customize_changeset_uuid', $query_params);
661
        $this->assertArrayNotHasKey('customize_theme', $query_params);
662
        $this->assertEquals($uuid, $query_params['customize_changeset_uuid']);
663
        $this->assertEquals($messenger_channel, $query_params['customize_messenger_channel']);
664
665
        $uuid = wp_generate_uuid4();
666
        $wp_customize = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
667
            array(
668
            'changeset_uuid' => $uuid,
669
            'messenger_channel' => null,
670
            'theme' => $preview_theme,
671
            ) 
672
        );
673
        $url = $wp_customize->add_state_query_params(home_url('/'));
674
        $parsed_url = wp_parse_url($url);
675
        parse_str($parsed_url['query'], $query_params);
676
        $this->assertArrayNotHasKey('customize_messenger_channel', $query_params);
677
        $this->assertArrayHasKey('customize_changeset_uuid', $query_params);
678
        $this->assertArrayHasKey('customize_theme', $query_params);
679
        $this->assertEquals($uuid, $query_params['customize_changeset_uuid']);
680
        $this->assertEquals($preview_theme, $query_params['customize_theme']);
681
682
        $uuid = wp_generate_uuid4();
683
        $wp_customize = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
684
            array(
685
            'changeset_uuid' => $uuid,
686
            'messenger_channel' => null,
687
            'theme' => $preview_theme,
688
            ) 
689
        );
690
        $url = $wp_customize->add_state_query_params('http://not-allowed.example.com/?q=1');
691
        $parsed_url = wp_parse_url($url);
692
        parse_str($parsed_url['query'], $query_params);
693
        $this->assertArrayNotHasKey('customize_messenger_channel', $query_params);
694
        $this->assertArrayNotHasKey('customize_changeset_uuid', $query_params);
695
        $this->assertArrayNotHasKey('customize_theme', $query_params);
696
    }
697
698
    /**
699
     * Test WP_Customize_Manager::save_changeset_post().
700
     *
701
     * @ticket 30937
702
     * @covers WP_Customize_Manager::save_changeset_post()
703
     */
704
    function test_save_changeset_post_without_theme_activation() 
705
    {
706
        global $wp_customize;
707
        wp_set_current_user(self::$admin_user_id);
708
709
        $did_action = array(
710
         'customize_save_validation_before' => did_action('customize_save_validation_before'),
711
         'customize_save' => did_action('customize_save'),
712
         'customize_save_after' => did_action('customize_save_after'),
713
        );
714
        $uuid = wp_generate_uuid4();
715
716
        $wp_customize = $manager = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
717
            array(
718
            'changeset_uuid' => $uuid,
719
            ) 
720
        );
721
        $wp_customize = $manager;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
722
        $manager->register_controls();
723
        $manager->set_post_value('blogname', 'Changeset Title');
724
        $manager->set_post_value('blogdescription', 'Changeset Tagline');
725
726
        $pre_saved_data = array(
727
         'blogname' => array(
728
          'value' => 'Overridden Changeset Title',
729
         ),
730
         'blogdescription' => array(
731
          'custom' => 'something',
732
         ),
733
        );
734
        $date = ( gmdate('Y') + 1 ) . '-12-01 00:00:00';
735
        $r = $manager->save_changeset_post(
736
            array(
737
            'status' => 'auto-draft',
738
            'title' => 'Auto Draft',
739
            'date_gmt' => $date,
740
            'data' => $pre_saved_data,
741
            ) 
742
        );
743
        $this->assertInternalType('array', $r);
744
745
        $this->assertEquals($did_action['customize_save_validation_before'] + 1, did_action('customize_save_validation_before'));
746
747
        $post_id = $manager->find_changeset_post_id($uuid);
748
        $this->assertNotNull($post_id);
749
        $saved_data = json_decode(get_post($post_id)->post_content, true);
750
        $this->assertEquals($manager->unsanitized_post_values(), wp_list_pluck($saved_data, 'value'));
751
        $this->assertEquals($pre_saved_data['blogname']['value'], $saved_data['blogname']['value']);
752
        $this->assertEquals($pre_saved_data['blogdescription']['custom'], $saved_data['blogdescription']['custom']);
753
        foreach ( $saved_data as $setting_id => $setting_params ) {
754
            $this->assertArrayHasKey('type', $setting_params);
755
            $this->assertEquals('option', $setting_params['type']);
756
            $this->assertArrayHasKey('user_id', $setting_params);
757
            $this->assertEquals(self::$admin_user_id, $setting_params['user_id']);
758
        }
759
        $this->assertEquals('Auto Draft', get_post($post_id)->post_title);
760
        $this->assertEquals('auto-draft', get_post($post_id)->post_status);
761
        $this->assertEquals($date, get_post($post_id)->post_date_gmt);
762
        $this->assertNotEquals('Changeset Title', get_option('blogname'));
763
        $this->assertArrayHasKey('setting_validities', $r);
764
765
        // Test saving with invalid settings, ensuring transaction blocked.
766
        $previous_saved_data = $saved_data;
767
        $manager->add_setting(
768
            'foo_unauthorized', array(
769
            'capability' => 'do_not_allow',
770
            ) 
771
        );
772
        $manager->add_setting(
773
            'baz_illegal', array(
774
            'validate_callback' => array( $this, 'return_illegal_error' ),
775
            ) 
776
        );
777
        $r = $manager->save_changeset_post(
778
            array(
779
            'status' => 'auto-draft',
780
            'data' => array(
781
            'blogname' => array(
782
            'value' => 'OK',
783
            ),
784
            'foo_unauthorized' => array(
785
            'value' => 'No',
786
            ),
787
            'bar_unknown' => array(
788
            'value' => 'No',
789
            ),
790
            'baz_illegal' => array(
791
            'value' => 'No',
792
            ),
793
            ),
794
            ) 
795
        );
796
        $this->assertInstanceOf('WP_Error', $r);
797
        $this->assertEquals('transaction_fail', $r->get_error_code());
798
        $this->assertInternalType('array', $r->get_error_data());
799
        $this->assertArrayHasKey('setting_validities', $r->get_error_data());
800
        $error_data = $r->get_error_data();
801
        $this->assertArrayHasKey('blogname', $error_data['setting_validities']);
802
        $this->assertTrue($error_data['setting_validities']['blogname']);
803
        $this->assertArrayHasKey('foo_unauthorized', $error_data['setting_validities']);
804
        $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['foo_unauthorized']);
805
        $this->assertEquals('unauthorized', $error_data['setting_validities']['foo_unauthorized']->get_error_code());
806
        $this->assertArrayHasKey('bar_unknown', $error_data['setting_validities']);
807
        $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['bar_unknown']);
808
        $this->assertEquals('unrecognized', $error_data['setting_validities']['bar_unknown']->get_error_code());
809
        $this->assertArrayHasKey('baz_illegal', $error_data['setting_validities']);
810
        $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['baz_illegal']);
811
        $this->assertEquals('illegal', $error_data['setting_validities']['baz_illegal']->get_error_code());
812
813
        // Since transactional, ensure no changes have been made.
814
        $this->assertEquals($previous_saved_data, json_decode(get_post($post_id)->post_content, true));
815
816
        // Attempt a non-transactional/incremental update.
817
        $wp_customize = $manager = new WP_Customize_Manager(
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
818
            array(
819
            'changeset_uuid' => $uuid,
820
            ) 
821
        );
822
        $wp_customize = $manager;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
823
        $manager->register_controls(); // That is, register settings.
824
        $r = $manager->save_changeset_post(
825
            array(
826
            'status' => null,
827
            'data' => array(
828
            'blogname' => array(
829
            'value' => 'Non-Transactional \o/ <script>unsanitized</script>',
830
            ),
831
            'bar_unknown' => array(
832
            'value' => 'No',
833
            ),
834
            ),
835
            ) 
836
        );
837
        $this->assertInternalType('array', $r);
838
        $this->assertArrayHasKey('setting_validities', $r);
839
        $this->assertTrue($r['setting_validities']['blogname']);
840
        $this->assertInstanceOf('WP_Error', $r['setting_validities']['bar_unknown']);
841
        $saved_data = json_decode(get_post($post_id)->post_content, true);
842
        $this->assertNotEquals($previous_saved_data, $saved_data);
843
        $this->assertEquals('Non-Transactional \o/ <script>unsanitized</script>', $saved_data['blogname']['value']);
844
845
        // Ensure the filter applies.
846
        $customize_changeset_save_data_call_count = $this->customize_changeset_save_data_call_count;
847
        add_filter('customize_changeset_save_data', array( $this, 'filter_customize_changeset_save_data' ), 10, 2);
848
        $manager->save_changeset_post(
849
            array(
850
            'status' => null,
851
            'data' => array(
852
            'blogname' => array(
853
            'value' => 'Filtered',
854
            ),
855
            ),
856
            ) 
857
        );
858
        $this->assertEquals($customize_changeset_save_data_call_count + 1, $this->customize_changeset_save_data_call_count);
859
860
        // Publish the changeset: actions will be doubled since also trashed.
861
        $expected_actions = array(
862
         'wp_trash_post' => 1,
863
         'clean_post_cache' => 2,
864
         'transition_post_status' => 2,
865
         'publish_to_trash' => 1,
866
         'trash_customize_changeset' => 1,
867
         'edit_post' => 2,
868
         'save_post_customize_changeset' => 2,
869
         'save_post' => 2,
870
         'wp_insert_post' => 2,
871
         'trashed_post' => 1,
872
        );
873
        $action_counts = array();
874
        foreach ( array_keys($expected_actions) as $action_name ) {
875
               $action_counts[ $action_name ] = did_action($action_name);
876
        }
877
878
        $wp_customize = $manager = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
879
        do_action('customize_register', $wp_customize);
880
        $manager->add_setting(
881
            'scratchpad', array(
882
            'type' => 'option',
883
            'capability' => 'exist',
884
            ) 
885
        );
886
        $manager->get_setting('blogname')->capability = 'exist';
887
        $original_capabilities = wp_list_pluck($manager->settings(), 'capability');
888
        wp_set_current_user(self::$subscriber_user_id);
889
        $r = $manager->save_changeset_post(
890
            array(
891
            'status' => 'publish',
892
            'data' => array(
893
            'blogname' => array(
894
            'value' => 'Do it live \o/',
895
            ),
896
            'scratchpad' => array(
897
            'value' => '<script>console.info( "HELLO" )</script>',
898
            ),
899
            ),
900
            ) 
901
        );
902
        $this->assertInternalType('array', $r);
903
        $this->assertEquals('Do it live \o/', get_option('blogname'));
904
        $this->assertEquals('trash', get_post_status($post_id)); // Auto-trashed.
905
        $this->assertEquals($original_capabilities, wp_list_pluck($manager->settings(), 'capability'));
906
        $this->assertContains('<script>', get_post($post_id)->post_content);
907
        $this->assertEquals($manager->changeset_uuid(), get_post($post_id)->post_name, 'Expected that the "__trashed" suffix to not be added.');
908
        wp_set_current_user(self::$admin_user_id);
909
        $this->assertEquals('publish', get_post_meta($post_id, '_wp_trash_meta_status', true));
910
        $this->assertTrue(is_numeric(get_post_meta($post_id, '_wp_trash_meta_time', true)));
911
912
        foreach ( array_keys($expected_actions) as $action_name ) {
913
             $this->assertEquals($expected_actions[ $action_name ] + $action_counts[ $action_name ], did_action($action_name), "Action: $action_name");
914
        }
915
916
        // Test revisions.
917
        add_post_type_support('customize_changeset', 'revisions');
918
        $uuid = wp_generate_uuid4();
919
        $wp_customize = $manager = new WP_Customize_Manager(array( 'changeset_uuid' => $uuid ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
920
        do_action('customize_register', $manager);
921
922
        $manager->set_post_value('blogname', 'Hello Surface');
923
        $manager->save_changeset_post(array( 'status' => 'auto-draft' ));
924
925
        $manager->set_post_value('blogname', 'Hello World');
926
        $manager->save_changeset_post(array( 'status' => 'draft' ));
927
        $this->assertTrue(wp_revisions_enabled(get_post($manager->changeset_post_id())));
928
929
        $manager->set_post_value('blogname', 'Hello Solar System');
930
        $manager->save_changeset_post(array( 'status' => 'draft' ));
931
932
        $manager->set_post_value('blogname', 'Hello Galaxy');
933
        $manager->save_changeset_post(array( 'status' => 'draft' ));
934
        $this->assertCount(3, wp_get_post_revisions($manager->changeset_post_id()));
935
    }
936
937
    /**
938
     * Call count for customize_changeset_save_data filter.
939
     *
940
     * @var int
941
     */
942
    protected $customize_changeset_save_data_call_count = 0;
943
944
    /**
945
     * Filter customize_changeset_save_data.
946
     *
947
     * @param   array $data    Data.
948
     * @param   array $context Context.
949
     * @returns array Data.
950
     */
951
    function filter_customize_changeset_save_data( $data, $context ) 
952
    {
953
        $this->customize_changeset_save_data_call_count += 1;
954
        $this->assertInternalType('array', $data);
955
        $this->assertInternalType('array', $context);
956
        $this->assertArrayHasKey('uuid', $context);
957
        $this->assertArrayHasKey('title', $context);
958
        $this->assertArrayHasKey('status', $context);
959
        $this->assertArrayHasKey('date_gmt', $context);
960
        $this->assertArrayHasKey('post_id', $context);
961
        $this->assertArrayHasKey('previous_data', $context);
962
        $this->assertArrayHasKey('manager', $context);
963
        return $data;
964
    }
965
966
    /**
967
     * Return illegal error.
968
     *
969
     * @return WP_Error Error.
970
     */
971
    function return_illegal_error() 
972
    {
973
        return new WP_Error('illegal');
974
    }
975
976
    /**
977
     * Test WP_Customize_Manager::save_changeset_post().
978
     *
979
     * @ticket 30937
980
     * @covers WP_Customize_Manager::save_changeset_post()
981
     * @covers WP_Customize_Manager::update_stashed_theme_mod_settings()
982
     */
983
    function test_save_changeset_post_with_theme_activation() 
984
    {
985
        global $wp_customize;
986
        wp_set_current_user(self::$admin_user_id);
987
988
        $preview_theme = $this->get_inactive_core_theme();
989
        $stashed_theme_mods = array(
990
         $preview_theme => array(
991
          'background_color' => array(
992
        'value' => '#123456',
993
          ),
994
         ),
995
        );
996
        update_option('customize_stashed_theme_mods', $stashed_theme_mods);
997
        $uuid = wp_generate_uuid4();
998
        $manager = new WP_Customize_Manager(
999
            array(
1000
            'changeset_uuid' => $uuid,
1001
            'theme' => $preview_theme,
1002
            ) 
1003
        );
1004
        $wp_customize = $manager;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1005
        do_action('customize_register', $manager);
1006
1007
        $manager->set_post_value('blogname', 'Hello Preview Theme');
1008
        $post_values = $manager->unsanitized_post_values();
1009
        $manager->save_changeset_post(array( 'status' => 'publish' )); // Activate.
1010
1011
        $this->assertEquals('#123456', $post_values['background_color']);
1012
        $this->assertEquals($preview_theme, get_stylesheet());
1013
        $this->assertEquals('Hello Preview Theme', get_option('blogname'));
1014
    }
1015
1016
    /**
1017
     * Test saving changesets with varying users and capabilities.
1018
     *
1019
     * @ticket 38705
1020
     * @covers WP_Customize_Manager::save_changeset_post()
1021
     */
1022
    function test_save_changeset_post_with_varying_users() 
1023
    {
1024
        global $wp_customize;
1025
1026
        add_theme_support('custom-background');
1027
        wp_set_current_user(self::$admin_user_id);
1028
        $other_admin_user_id = self::factory()->user->create(array( 'role' => 'administrator' ));
1029
1030
        $uuid = wp_generate_uuid4();
1031
        $wp_customize = $this->create_test_manager($uuid);
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1032
        $r = $wp_customize->save_changeset_post(
1033
            array(
1034
            'status' => 'auto-draft',
1035
            'data' => array(
1036
            'blogname' => array(
1037
            'value' => 'Admin 1 Title',
1038
            ),
1039
            'scratchpad' => array(
1040
            'value' => 'Admin 1 Scratch',
1041
            ),
1042
            'background_color' => array(
1043
            'value' => '#000000',
1044
            ),
1045
            ),
1046
            ) 
1047
        );
1048
        $this->assertInternalType('array', $r);
1049
        $this->assertEquals(
1050
            array_fill_keys(array( 'blogname', 'scratchpad', 'background_color' ), true),
1051
            $r['setting_validities']
1052
        );
1053
        $post_id = $wp_customize->find_changeset_post_id($uuid);
1054
        $data = json_decode(get_post($post_id)->post_content, true);
1055
        $this->assertEquals(self::$admin_user_id, $data['blogname']['user_id']);
1056
        $this->assertEquals(self::$admin_user_id, $data['scratchpad']['user_id']);
1057
        $this->assertEquals(self::$admin_user_id, $data[ $this->manager->get_stylesheet() . '::background_color' ]['user_id']);
1058
1059
        // Attempt to save just one setting under a different user.
1060
        wp_set_current_user($other_admin_user_id);
1061
        $wp_customize = $this->create_test_manager($uuid);
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1062
        $r = $wp_customize->save_changeset_post(
1063
            array(
1064
            'status' => 'auto-draft',
1065
            'data' => array(
1066
            'blogname' => array(
1067
            'value' => 'Admin 2 Title',
1068
            ),
1069
            'background_color' => array(
1070
            'value' => '#FFFFFF',
1071
            ),
1072
            ),
1073
            ) 
1074
        );
1075
        $this->assertInternalType('array', $r);
1076
        $this->assertEquals(
1077
            array_fill_keys(array( 'blogname', 'background_color' ), true),
1078
            $r['setting_validities']
1079
        );
1080
        $data = json_decode(get_post($post_id)->post_content, true);
1081
        $this->assertEquals('Admin 2 Title', $data['blogname']['value']);
1082
        $this->assertEquals($other_admin_user_id, $data['blogname']['user_id']);
1083
        $this->assertEquals('Admin 1 Scratch', $data['scratchpad']['value']);
1084
        $this->assertEquals(self::$admin_user_id, $data['scratchpad']['user_id']);
1085
        $this->assertEquals('#FFFFFF', $data[ $this->manager->get_stylesheet() . '::background_color' ]['value']);
1086
        $this->assertEquals($other_admin_user_id, $data[ $this->manager->get_stylesheet() . '::background_color' ]['user_id']);
1087
1088
        // Attempt to save now as under-privileged user.
1089
        $wp_customize = $this->create_test_manager($uuid);
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1090
        $r = $wp_customize->save_changeset_post(
1091
            array(
1092
            'status' => 'auto-draft',
1093
            'data' => array(
1094
            'blogname' => array(
1095
            'value' => 'Admin 2 Title', // Identical to what is already in the changeset so will be skipped.
1096
            ),
1097
            'scratchpad' => array(
1098
            'value' => 'Subscriber Scratch',
1099
            ),
1100
            ),
1101
            'user_id' => self::$subscriber_user_id,
1102
            ) 
1103
        );
1104
        $this->assertInternalType('array', $r);
1105
        $this->assertEquals(
1106
            array_fill_keys(array( 'scratchpad', 'blogname' ), true),
1107
            $r['setting_validities']
1108
        );
1109
        $data = json_decode(get_post($post_id)->post_content, true);
1110
        $this->assertEquals($other_admin_user_id, $data['blogname']['user_id'], 'Expected setting to be untouched.');
1111
        $this->assertEquals(self::$subscriber_user_id, $data['scratchpad']['user_id']);
1112
        $this->assertEquals($other_admin_user_id, $data[ $this->manager->get_stylesheet() . '::background_color' ]['user_id']);
1113
1114
        // Manually update the changeset so that the user_id context is not included.
1115
        $data = json_decode(get_post($post_id)->post_content, true);
1116
        $data['blogdescription']['value'] = 'Programmatically-supplied Tagline';
1117
        wp_update_post(wp_slash(array( 'ID' => $post_id, 'post_content' => wp_json_encode($data) )));
1118
1119
        // Ensure the modifying user set as the current user when each is saved, simulating WP Cron envronment.
1120
        wp_set_current_user(0);
1121
        $save_counts = array();
1122 View Code Duplication
        foreach ( array_keys($data) as $setting_id ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1123
               $setting_id = preg_replace('/^.+::/', '', $setting_id);
1124
               $save_counts[ $setting_id ] = did_action(sprintf('customize_save_%s', $setting_id));
1125
        }
1126
        $this->filtered_setting_current_user_ids = array();
1127
        foreach ( $wp_customize->settings() as $setting ) {
1128
             add_filter(sprintf('customize_sanitize_%s', $setting->id), array( $this, 'filter_customize_setting_to_log_current_user' ), 10, 2);
1129
        }
1130
        wp_update_post(array( 'ID' => $post_id, 'post_status' => 'publish' ));
1131 View Code Duplication
        foreach ( array_keys($data) as $setting_id ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1132
             $setting_id = preg_replace('/^.+::/', '', $setting_id);
1133
             $this->assertEquals($save_counts[ $setting_id ] + 1, did_action(sprintf('customize_save_%s', $setting_id)), $setting_id);
1134
        }
1135
        $this->assertEqualSets(array( 'blogname', 'blogdescription', 'background_color', 'scratchpad' ), array_keys($this->filtered_setting_current_user_ids));
1136
        $this->assertEquals($other_admin_user_id, $this->filtered_setting_current_user_ids['blogname']);
1137
        $this->assertEquals(0, $this->filtered_setting_current_user_ids['blogdescription']);
1138
        $this->assertEquals(self::$subscriber_user_id, $this->filtered_setting_current_user_ids['scratchpad']);
1139
        $this->assertEquals($other_admin_user_id, $this->filtered_setting_current_user_ids['background_color']);
1140
        $this->assertEquals('Subscriber Scratch', get_option('scratchpad'));
1141
    }
1142
1143
    /**
1144
     * Create test manager.
1145
     *
1146
     * @param  string $uuid Changeset UUID.
1147
     * @return WP_Customize_Manager Manager.
1148
     */
1149
    protected function create_test_manager( $uuid ) 
1150
    {
1151
        $manager = new WP_Customize_Manager(
1152
            array(
1153
            'changeset_uuid' => $uuid,
1154
            ) 
1155
        );
1156
        do_action('customize_register', $manager);
1157
        $manager->add_setting(
1158
            'blogfounded', array(
1159
            'type' => 'option',
1160
            ) 
1161
        );
1162
        $manager->add_setting(
1163
            'blogterminated', array(
1164
            'type' => 'option',
1165
            'capability' => 'do_not_allow',
1166
            ) 
1167
        );
1168
        $manager->add_setting(
1169
            'scratchpad', array(
1170
            'type' => 'option',
1171
            'capability' => 'exist',
1172
            ) 
1173
        );
1174
        return $manager;
1175
    }
1176
1177
    /**
1178
     * Test writing changesets when user supplies unchanged values.
1179
     *
1180
     * @ticket 38865
1181
     * @covers WP_Customize_Manager::save_changeset_post()
1182
     */
1183
    function test_save_changeset_post_with_unchanged_values() 
1184
    {
1185
        global $wp_customize;
1186
1187
        add_theme_support('custom-background');
1188
        wp_set_current_user(self::$admin_user_id);
1189
        $other_admin_user_id = self::factory()->user->create(array( 'role' => 'administrator' ));
1190
1191
        $uuid = wp_generate_uuid4();
1192
        $wp_customize = $this->create_test_manager($uuid);
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1193
        $wp_customize->save_changeset_post(
1194
            array(
1195
            'status' => 'auto-draft',
1196
            'data' => array(
1197
            'blogname' => array(
1198
            'value' => 'Admin 1 Title',
1199
            ),
1200
            'blogdescription' => array(
1201
            'value' => 'Admin 1 Tagline',
1202
            ),
1203
            'blogfounded' => array(
1204
            'value' => '2016',
1205
            ),
1206
            'scratchpad' => array(
1207
            'value' => 'Admin 1 Scratch',
1208
            ),
1209
            ),
1210
            ) 
1211
        );
1212
1213
        // Make sure that setting properties of unknown and unauthorized settings are rejected.
1214
        $data = get_post($wp_customize->changeset_post_id())->post_content;
1215
        $r = $wp_customize->save_changeset_post(
1216
            array(
1217
            'data' => array(
1218
            'unknownsetting' => array(
1219
            'custom' => 'prop',
1220
            ),
1221
            'blogterminated' => array(
1222
            'custom' => 'prop',
1223
            ),
1224
            ),
1225
            ) 
1226
        );
1227
        $this->assertInstanceOf('WP_Error', $r['setting_validities']['unknownsetting']);
1228
        $this->assertEquals('unrecognized', $r['setting_validities']['unknownsetting']->get_error_code());
1229
        $this->assertInstanceOf('WP_Error', $r['setting_validities']['blogterminated']);
1230
        $this->assertEquals('unauthorized', $r['setting_validities']['blogterminated']->get_error_code());
1231
        $this->assertEquals($data, get_post($wp_customize->changeset_post_id())->post_content);
1232
1233
        // Test submitting data with changed and unchanged settings, creating a new instance so that the post_values are cleared.
1234
        wp_set_current_user($other_admin_user_id);
1235
        $wp_customize = $this->create_test_manager($uuid);
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1236
        $r = $wp_customize->save_changeset_post(
1237
            array(
1238
            'status' => 'auto-draft',
1239
            'data' => array(
1240
            'blogname' => array(
1241
            'value' => 'Admin 1 Title', // Unchanged value.
1242
            ),
1243
            'blogdescription' => array(
1244
            'value' => 'Admin 1 Tagline Changed', // Changed value.
1245
            ),
1246
            'blogfounded' => array(
1247
            'extra' => 'blogfounded_param', // New param.
1248
            ),
1249
            'scratchpad' => array(
1250
            'value' => 'Admin 1 Scratch', // Unchanged value.
1251
            'extra' => 'background_scratchpad2', // New param.
1252
            ),
1253
            ),
1254
            ) 
1255
        );
1256
1257
        // Note that blogfounded is not included among setting_validities because no value was supplied and it is not unrecognized/unauthorized.
1258
        $this->assertEquals(array_fill_keys(array( 'blogname', 'blogdescription', 'scratchpad' ), true), $r['setting_validities'], 'Expected blogname even though unchanged.');
1259
1260
        $data = json_decode(get_post($wp_customize->changeset_post_id())->post_content, true);
1261
1262
        $this->assertEquals(self::$admin_user_id, $data['blogname']['user_id'], 'Expected unchanged user_id since value was unchanged.');
1263
        $this->assertEquals($other_admin_user_id, $data['blogdescription']['user_id']);
1264
        $this->assertEquals($other_admin_user_id, $data['blogfounded']['user_id']);
1265
        $this->assertEquals($other_admin_user_id, $data['scratchpad']['user_id']);
1266
    }
1267
1268
    /**
1269
     * Test writing changesets and publishing with users who can unfiltered_html and those who cannot.
1270
     *
1271
     * @ticket 38705
1272
     * @covers WP_Customize_Manager::save_changeset_post()
1273
     */
1274
    function test_save_changeset_post_with_varying_unfiltered_html_cap() 
1275
    {
1276
        global $wp_customize;
1277
        grant_super_admin(self::$admin_user_id);
1278
        $this->assertTrue(user_can(self::$admin_user_id, 'unfiltered_html'));
1279
        $this->assertFalse(user_can(self::$subscriber_user_id, 'unfiltered_html'));
1280
        wp_set_current_user(0);
1281
        add_action('customize_register', array( $this, 'register_scratchpad_setting' ));
1282
1283
        // Attempt scratchpad with user who has unfiltered_html.
1284
        update_option('scratchpad', '');
1285
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1286
        do_action('customize_register', $wp_customize);
1287
        $wp_customize->set_post_value('scratchpad', 'Unfiltered<script>evil</script>');
1288
        $wp_customize->save_changeset_post(
1289
            array(
1290
            'status' => 'auto-draft',
1291
            'user_id' => self::$admin_user_id,
1292
            ) 
1293
        );
1294
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $wp_customize->changeset_uuid() ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1295
        do_action('customize_register', $wp_customize);
1296
        $wp_customize->save_changeset_post(array( 'status' => 'publish' ));
1297
        $this->assertEquals('Unfiltered<script>evil</script>', get_option('scratchpad'));
1298
1299
        // Attempt scratchpad with user who doesn't have unfiltered_html.
1300
        update_option('scratchpad', '');
1301
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1302
        do_action('customize_register', $wp_customize);
1303
        $wp_customize->set_post_value('scratchpad', 'Unfiltered<script>evil</script>');
1304
        $wp_customize->save_changeset_post(
1305
            array(
1306
            'status' => 'auto-draft',
1307
            'user_id' => self::$subscriber_user_id,
1308
            ) 
1309
        );
1310
        $wp_customize = new WP_Customize_Manager(array( 'changeset_uuid' => $wp_customize->changeset_uuid() ));
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1311
        do_action('customize_register', $wp_customize);
1312
        $wp_customize->save_changeset_post(array( 'status' => 'publish' ));
1313
        $this->assertEquals('Unfilteredevil', get_option('scratchpad'));
1314
1315
        // Attempt publishing scratchpad as anonymous user when changeset was set by privileged user.
1316
        update_option('scratchpad', '');
1317
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1318
        do_action('customize_register', $wp_customize);
1319
        $wp_customize->set_post_value('scratchpad', 'Unfiltered<script>evil</script>');
1320
        $wp_customize->save_changeset_post(
1321
            array(
1322
            'status' => 'auto-draft',
1323
            'user_id' => self::$admin_user_id,
1324
            ) 
1325
        );
1326
        $changeset_post_id = $wp_customize->changeset_post_id();
1327
        wp_set_current_user(0);
1328
        $wp_customize = null;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1329
        unset($GLOBALS['wp_actions']['customize_register']);
1330
        $this->assertEquals('Unfilteredevil', apply_filters('content_save_pre', 'Unfiltered<script>evil</script>'));
1331
        wp_publish_post($changeset_post_id); // @todo If wp_update_post() is used here, then kses will corrupt the post_content.
1332
        $this->assertEquals('Unfiltered<script>evil</script>', get_option('scratchpad'));
1333
    }
1334
1335
    /**
1336
     * Register scratchpad setting.
1337
     *
1338
     * @param WP_Customize_Manager $wp_customize Manager.
1339
     */
1340
    function register_scratchpad_setting( WP_Customize_Manager $wp_customize ) 
1341
    {
1342
        $wp_customize->add_setting(
1343
            'scratchpad', array(
1344
            'type' => 'option',
1345
            'capability' => 'exist',
1346
            'sanitize_callback' => array( $this, 'filter_sanitize_scratchpad' ),
1347
            ) 
1348
        );
1349
    }
1350
1351
    /**
1352
     * Sanitize scratchpad as if it is post_content so kses filters apply.
1353
     *
1354
     * @param  string $value Value.
1355
     * @return string Value.
1356
     */
1357
    function filter_sanitize_scratchpad( $value ) 
1358
    {
1359
        return apply_filters('content_save_pre', $value);
1360
    }
1361
1362
    /**
1363
     * Current user when settings are filtered.
1364
     *
1365
     * @var array
1366
     */
1367
    protected $filtered_setting_current_user_ids = array();
1368
1369
    /**
1370
     * Filter setting to capture the current user when the filter applies.
1371
     *
1372
     * @param  mixed                $value   Setting value.
1373
     * @param  WP_Customize_Setting $setting Setting.
1374
     * @return mixed Value.
1375
     */
1376
    function filter_customize_setting_to_log_current_user( $value, $setting ) 
1377
    {
1378
        $this->filtered_setting_current_user_ids[ $setting->id ] = get_current_user_id();
1379
        return $value;
1380
    }
1381
1382
    /**
1383
     * Test WP_Customize_Manager::is_cross_domain().
1384
     *
1385
     * @ticket 30937
1386
     * @covers WP_Customize_Manager::is_cross_domain()
1387
     */
1388
    function test_is_cross_domain() 
1389
    {
1390
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1391
1392
        update_option('home', 'http://example.com');
1393
        update_option('siteurl', 'http://example.com');
1394
        $this->assertFalse($wp_customize->is_cross_domain());
1395
1396
        update_option('home', 'http://example.com');
1397
        update_option('siteurl', 'https://admin.example.com');
1398
        $this->assertTrue($wp_customize->is_cross_domain());
1399
    }
1400
1401
    /**
1402
     * Test WP_Customize_Manager::get_allowed_urls().
1403
     *
1404
     * @ticket 30937
1405
     * @covers WP_Customize_Manager::get_allowed_urls()
1406
     */
1407
    function test_get_allowed_urls() 
1408
    {
1409
        $wp_customize = new WP_Customize_Manager();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1410
        $this->assertFalse(is_ssl());
1411
        $this->assertFalse($wp_customize->is_cross_domain());
1412
        $allowed = $wp_customize->get_allowed_urls();
1413
        $this->assertEquals($allowed, array( home_url('/', 'http') ));
1414
1415
        add_filter('customize_allowed_urls', array( $this, 'filter_customize_allowed_urls' ));
1416
        $allowed = $wp_customize->get_allowed_urls();
1417
        $this->assertEqualSets($allowed, array( 'http://headless.example.com/', home_url('/', 'http') ));
1418
    }
1419
1420
    /**
1421
     * Callback for customize_allowed_urls filter.
1422
     *
1423
     * @param  array $urls URLs.
1424
     * @return array URLs.
1425
     */
1426
    function filter_customize_allowed_urls( $urls ) 
1427
    {
1428
        $urls[] = 'http://headless.example.com/';
1429
        return $urls;
1430
    }
1431
1432
    /**
1433
     * Test WP_Customize_Manager::doing_ajax().
1434
     *
1435
     * @group ajax
1436
     */
1437
    function test_doing_ajax() 
1438
    {
1439
        if (! defined('DOING_AJAX') ) {
0 ignored issues
show
introduced by
Expected 1 space before "!"; 0 found
Loading history...
1440
            define('DOING_AJAX', true);
1441
        }
1442
1443
        $manager = $this->manager;
1444
        $this->assertTrue($manager->doing_ajax());
1445
1446
        $_REQUEST['action'] = 'customize_save';
1447
        $this->assertTrue($manager->doing_ajax('customize_save'));
1448
        $this->assertFalse($manager->doing_ajax('update-widget'));
1449
    }
1450
1451
    /**
1452
     * Test ! WP_Customize_Manager::doing_ajax().
1453
     */
1454
    function test_not_doing_ajax() 
1455
    {
1456
        if (defined('DOING_AJAX') && DOING_AJAX ) {
1457
            $this->markTestSkipped('Cannot test when DOING_AJAX');
1458
        }
1459
1460
        $manager = $this->manager;
1461
        $this->assertFalse($manager->doing_ajax());
1462
    }
1463
1464
    /**
1465
     * Test WP_Customize_Manager::unsanitized_post_values().
1466
     *
1467
     * @ticket 30988
1468
     */
1469
    function test_unsanitized_post_values_from_input() 
1470
    {
1471
        wp_set_current_user(self::$admin_user_id);
1472
        $manager = $this->manager;
1473
1474
        $customized = array(
1475
         'foo' => 'bar',
1476
         'baz[quux]' => 123,
1477
        );
1478
        $_POST['customized'] = wp_slash(wp_json_encode($customized));
1479
        $post_values = $manager->unsanitized_post_values();
1480
        $this->assertEquals($customized, $post_values);
1481
        $this->assertEmpty($manager->unsanitized_post_values(array( 'exclude_post_data' => true )));
1482
1483
        $manager->set_post_value('foo', 'BAR');
1484
        $post_values = $manager->unsanitized_post_values();
1485
        $this->assertEquals('BAR', $post_values['foo']);
1486
        $this->assertEmpty($manager->unsanitized_post_values(array( 'exclude_post_data' => true )));
1487
1488
        // If user is unprivileged, the post data is ignored.
1489
        wp_set_current_user(0);
1490
        $this->assertEmpty($manager->unsanitized_post_values());
1491
    }
1492
1493
    /**
1494
     * Test WP_Customize_Manager::unsanitized_post_values().
1495
     *
1496
     * @ticket 30937
1497
     * @covers WP_Customize_Manager::unsanitized_post_values()
1498
     */
1499
    function test_unsanitized_post_values_with_changeset_and_stashed_theme_mods() 
1500
    {
1501
        wp_set_current_user(self::$admin_user_id);
1502
1503
        $preview_theme = $this->get_inactive_core_theme();
1504
        $stashed_theme_mods = array(
1505
         $preview_theme => array(
1506
          'background_color' => array(
1507
        'value' => '#000000',
1508
          ),
1509
         ),
1510
        );
1511
        $stashed_theme_mods[ get_stylesheet() ] = array(
1512
         'background_color' => array(
1513
          'value' => '#FFFFFF',
1514
         ),
1515
        );
1516
        update_option('customize_stashed_theme_mods', $stashed_theme_mods);
1517
1518
        $post_values = array(
1519
         'blogdescription' => 'Post Input Tagline',
1520
        );
1521
        $_POST['customized'] = wp_slash(wp_json_encode($post_values));
1522
1523
        $uuid = wp_generate_uuid4();
1524
        $changeset_data = array(
1525
         'blogname' => array(
1526
          'value' => 'Changeset Title',
1527
         ),
1528
         'blogdescription' => array(
1529
          'value' => 'Changeset Tagline',
1530
         ),
1531
        );
1532
        $this->factory()->post->create(
1533
            array(
1534
            'post_type' => 'customize_changeset',
1535
            'post_status' => 'auto-draft',
1536
            'post_name' => $uuid,
1537
            'post_content' => wp_json_encode($changeset_data),
1538
            ) 
1539
        );
1540
1541
        $manager = new WP_Customize_Manager(
1542
            array(
1543
            'changeset_uuid' => $uuid,
1544
            ) 
1545
        );
1546
        $this->assertTrue($manager->is_theme_active());
1547
1548
        $this->assertArrayNotHasKey('background_color', $manager->unsanitized_post_values());
1549
1550
        $this->assertEquals(
1551
            array(
1552
            'blogname' => 'Changeset Title',
1553
            'blogdescription' => 'Post Input Tagline',
1554
            ),
1555
            $manager->unsanitized_post_values()
1556
        );
1557
        $this->assertEquals(
1558
            array(
1559
            'blogdescription' => 'Post Input Tagline',
1560
            ),
1561
            $manager->unsanitized_post_values(array( 'exclude_changeset' => true ))
1562
        );
1563
1564
        $manager->set_post_value('blogdescription', 'Post Override Tagline');
1565
        $this->assertEquals(
1566
            array(
1567
            'blogname' => 'Changeset Title',
1568
            'blogdescription' => 'Post Override Tagline',
1569
            ),
1570
            $manager->unsanitized_post_values()
1571
        );
1572
1573
        $this->assertEquals(
1574
            array(
1575
            'blogname' => 'Changeset Title',
1576
            'blogdescription' => 'Changeset Tagline',
1577
            ),
1578
            $manager->unsanitized_post_values(array( 'exclude_post_data' => true ))
1579
        );
1580
1581
        $this->assertEmpty($manager->unsanitized_post_values(array( 'exclude_post_data' => true, 'exclude_changeset' => true )));
1582
1583
        // Test unstashing theme mods.
1584
        $manager = new WP_Customize_Manager(
1585
            array(
1586
            'changeset_uuid' => $uuid,
1587
            'theme' => $preview_theme,
1588
            ) 
1589
        );
1590
        $this->assertFalse($manager->is_theme_active());
1591
        $values = $manager->unsanitized_post_values(array( 'exclude_post_data' => true, 'exclude_changeset' => true ));
1592
        $this->assertNotEmpty($values);
1593
        $this->assertArrayHasKey('background_color', $values);
1594
        $this->assertEquals('#000000', $values['background_color']);
1595
1596
        $values = $manager->unsanitized_post_values(array( 'exclude_post_data' => false, 'exclude_changeset' => false ));
1597
        $this->assertArrayHasKey('background_color', $values);
1598
        $this->assertArrayHasKey('blogname', $values);
1599
        $this->assertArrayHasKey('blogdescription', $values);
1600
    }
1601
1602
    /**
1603
     * Test the WP_Customize_Manager::post_value() method.
1604
     *
1605
     * @ticket 30988
1606
     */
1607
    function test_post_value() 
1608
    {
1609
        wp_set_current_user(self::$admin_user_id);
1610
        $posted_settings = array(
1611
         'foo' => 'OOF',
1612
        );
1613
        $_POST['customized'] = wp_slash(wp_json_encode($posted_settings));
1614
1615
        $manager = $this->manager;
1616
1617
        $manager->add_setting('foo', array( 'default' => 'foo_default' ));
1618
        $foo_setting = $manager->get_setting('foo');
1619
        $this->assertEquals('foo_default', $manager->get_setting('foo')->value(), 'Expected non-previewed setting to return default when value() method called.');
1620
        $this->assertEquals($posted_settings['foo'], $manager->post_value($foo_setting, 'post_value_foo_default'), 'Expected post_value($foo_setting) to return value supplied in $_POST[customized][foo]');
1621
1622
        $manager->add_setting('bar', array( 'default' => 'bar_default' ));
1623
        $bar_setting = $manager->get_setting('bar');
1624
        $this->assertEquals('post_value_bar_default', $manager->post_value($bar_setting, 'post_value_bar_default'), 'Expected post_value($bar_setting, $default) to return $default since no value supplied in $_POST[customized][bar]');
1625
    }
1626
1627
    /**
1628
     * Test the WP_Customize_Manager::post_value() method for a setting value that fails validation.
1629
     *
1630
     * @ticket 34893
1631
     */
1632
    function test_invalid_post_value() 
1633
    {
1634
        wp_set_current_user(self::$admin_user_id);
1635
        $default_value = 'foo_default';
1636
        $setting = $this->manager->add_setting(
1637
            'foo', array(
1638
            'validate_callback' => array( $this, 'filter_customize_validate_foo' ),
1639
            'sanitize_callback' => array( $this, 'filter_customize_sanitize_foo' ),
1640
            ) 
1641
        );
1642
        $this->assertEquals($default_value, $this->manager->post_value($setting, $default_value));
1643
        $this->assertEquals($default_value, $setting->post_value($default_value));
1644
1645
        $post_value = 'bar';
1646
        $this->manager->set_post_value('foo', $post_value);
1647
        $this->assertEquals(strtoupper($post_value), $this->manager->post_value($setting, $default_value));
1648
        $this->assertEquals(strtoupper($post_value), $setting->post_value($default_value));
1649
1650
        $this->manager->set_post_value('foo', 'return_wp_error_in_sanitize');
1651
        $this->assertEquals($default_value, $this->manager->post_value($setting, $default_value));
1652
        $this->assertEquals($default_value, $setting->post_value($default_value));
1653
1654
        $this->manager->set_post_value('foo', 'return_null_in_sanitize');
1655
        $this->assertEquals($default_value, $this->manager->post_value($setting, $default_value));
1656
        $this->assertEquals($default_value, $setting->post_value($default_value));
1657
1658
        $post_value = '<script>evil</script>';
1659
        $this->manager->set_post_value('foo', $post_value);
1660
        $this->assertEquals($default_value, $this->manager->post_value($setting, $default_value));
1661
        $this->assertEquals($default_value, $setting->post_value($default_value));
1662
    }
1663
1664
    /**
1665
     * Filter customize_validate callback.
1666
     *
1667
     * @param  mixed $value Value.
1668
     * @return string|WP_Error
1669
     */
1670
    function filter_customize_sanitize_foo( $value ) 
1671
    {
1672
        if ('return_null_in_sanitize' === $value ) {
1673
            $value = null;
1674
        } elseif (is_string($value) ) {
1675
            $value = strtoupper($value);
1676
            if (false !== stripos($value, 'return_wp_error_in_sanitize') ) {
1677
                $value = new WP_Error('invalid_value_in_sanitize', __('Invalid value.'), array( 'source' => 'filter_customize_sanitize_foo' ));
1678
            }
1679
        }
1680
        return $value;
1681
    }
1682
1683
    /**
1684
     * Filter customize_validate callback.
1685
     *
1686
     * @param  WP_Error $validity Validity.
1687
     * @param  mixed    $value    Value.
1688
     * @return WP_Error
1689
     */
1690
    function filter_customize_validate_foo( $validity, $value ) 
1691
    {
1692
        if (false !== stripos($value, '<script') ) {
1693
            $validity->add('invalid_value_in_validate', __('Invalid value.'), array( 'source' => 'filter_customize_validate_foo' ));
1694
        }
1695
        return $validity;
1696
    }
1697
1698
    /**
1699
     * Test the WP_Customize_Manager::post_value() method to make sure that the validation and sanitization are done in the right order.
1700
     *
1701
     * @ticket 37247
1702
     */
1703
    function test_post_value_validation_sanitization_order() 
1704
    {
1705
        wp_set_current_user(self::$admin_user_id);
1706
        $default_value = '0';
1707
        $setting = $this->manager->add_setting(
1708
            'numeric', array(
1709
            'validate_callback' => array( $this, 'filter_customize_validate_numeric' ),
1710
            'sanitize_callback' => array( $this, 'filter_customize_sanitize_numeric' ),
1711
            ) 
1712
        );
1713
        $this->assertEquals($default_value, $this->manager->post_value($setting, $default_value));
1714
        $this->assertEquals($default_value, $setting->post_value($default_value));
1715
1716
        $post_value = '42';
1717
        $this->manager->set_post_value('numeric', $post_value);
1718
        $this->assertEquals($post_value, $this->manager->post_value($setting, $default_value));
1719
        $this->assertEquals($post_value, $setting->post_value($default_value));
1720
    }
1721
1722
    /**
1723
     * Filter customize_validate callback for a numeric value.
1724
     *
1725
     * @param  mixed $value Value.
1726
     * @return string|WP_Error
1727
     */
1728
    function filter_customize_sanitize_numeric( $value ) 
1729
    {
1730
        return absint($value);
1731
    }
1732
1733
    /**
1734
     * Filter customize_validate callback for a numeric value.
1735
     *
1736
     * @param  WP_Error $validity Validity.
1737
     * @param  mixed    $value    Value.
1738
     * @return WP_Error
1739
     */
1740
    function filter_customize_validate_numeric( $validity, $value ) 
1741
    {
1742
        if (! is_string($value) || ! is_numeric($value) ) {
0 ignored issues
show
introduced by
Expected 1 space before "!"; 0 found
Loading history...
1743
            $validity->add('invalid_value_in_validate', __('Invalid value.'), array( 'source' => 'filter_customize_validate_numeric' ));
1744
        }
1745
        return $validity;
1746
    }
1747
1748
    /**
1749
     * Test WP_Customize_Manager::validate_setting_values().
1750
     *
1751
     * @see WP_Customize_Manager::validate_setting_values()
1752
     */
1753
    function test_validate_setting_values() 
1754
    {
1755
        wp_set_current_user(self::$admin_user_id);
1756
        $setting = $this->manager->add_setting(
1757
            'foo', array(
1758
            'validate_callback' => array( $this, 'filter_customize_validate_foo' ),
1759
            'sanitize_callback' => array( $this, 'filter_customize_sanitize_foo' ),
1760
            ) 
1761
        );
1762
1763
        $post_value = 'bar';
1764
        $this->manager->set_post_value('foo', $post_value);
1765
        $validities = $this->manager->validate_setting_values($this->manager->unsanitized_post_values());
1766
        $this->assertCount(1, $validities);
1767
        $this->assertEquals(array( 'foo' => true ), $validities);
1768
1769
        $this->manager->set_post_value('foo', 'return_wp_error_in_sanitize');
1770
        $invalid_settings = $this->manager->validate_setting_values($this->manager->unsanitized_post_values());
1771
        $this->assertCount(1, $invalid_settings);
1772
        $this->assertArrayHasKey($setting->id, $invalid_settings);
1773
        $this->assertInstanceOf('WP_Error', $invalid_settings[ $setting->id ]);
1774
        $error = $invalid_settings[ $setting->id ];
1775
        $this->assertEquals('invalid_value_in_sanitize', $error->get_error_code());
1776
        $this->assertEquals(array( 'source' => 'filter_customize_sanitize_foo' ), $error->get_error_data());
1777
1778
        $this->manager->set_post_value('foo', 'return_null_in_sanitize');
1779
        $invalid_settings = $this->manager->validate_setting_values($this->manager->unsanitized_post_values());
1780
        $this->assertCount(1, $invalid_settings);
1781
        $this->assertArrayHasKey($setting->id, $invalid_settings);
1782
        $this->assertInstanceOf('WP_Error', $invalid_settings[ $setting->id ]);
1783
        $this->assertNull($invalid_settings[ $setting->id ]->get_error_data());
1784
1785
        $post_value = '<script>evil</script>';
1786
        $this->manager->set_post_value('foo', $post_value);
1787
        $invalid_settings = $this->manager->validate_setting_values($this->manager->unsanitized_post_values());
1788
        $this->assertCount(1, $invalid_settings);
1789
        $this->assertArrayHasKey($setting->id, $invalid_settings);
1790
        $this->assertInstanceOf('WP_Error', $invalid_settings[ $setting->id ]);
1791
        $error = $invalid_settings[ $setting->id ];
1792
        $this->assertEquals('invalid_value_in_validate', $error->get_error_code());
1793
        $this->assertEquals(array( 'source' => 'filter_customize_validate_foo' ), $error->get_error_data());
1794
    }
1795
1796
    /**
1797
     * Test WP_Customize_Manager::validate_setting_values().
1798
     *
1799
     * @ticket 37638
1800
     * @covers WP_Customize_Manager::validate_setting_values()
1801
     */
1802
    function test_late_validate_setting_values() 
1803
    {
1804
        $setting = new Test_Setting_Without_Applying_Validate_Filter($this->manager, 'required');
1805
        $this->manager->add_setting($setting);
1806
1807
        $this->assertInstanceOf('WP_Error', $setting->validate(''));
1808
        $setting_validities = $this->manager->validate_setting_values(array( $setting->id => '' ));
1809
        $this->assertInstanceOf('WP_Error', $setting_validities[ $setting->id ]);
1810
1811
        $this->assertTrue($setting->validate('ok'));
1812
        $setting_validities = $this->manager->validate_setting_values(array( $setting->id => 'ok' ));
1813
        $this->assertTrue($setting_validities[ $setting->id ]);
1814
1815
        add_filter("customize_validate_{$setting->id}", array( $this, 'late_validate_length' ), 10, 3);
1816
        $this->assertTrue($setting->validate('bad'));
1817
        $setting_validities = $this->manager->validate_setting_values(array( $setting->id => 'bad' ));
1818
        $validity = $setting_validities[ $setting->id ];
1819
        $this->assertInstanceOf('WP_Error', $validity);
1820
        $this->assertEquals('minlength', $validity->get_error_code());
1821
    }
1822
1823
    /**
1824
     * Test WP_Customize_Manager::validate_setting_values().
1825
     *
1826
     * @ticket 30937
1827
     * @covers WP_Customize_Manager::validate_setting_values()
1828
     */
1829
    function test_validate_setting_values_args() 
1830
    {
1831
        wp_set_current_user(self::$admin_user_id);
1832
        $this->manager->register_controls();
1833
1834
        $validities = $this->manager->validate_setting_values(array( 'unknown' => 'X' ));
1835
        $this->assertEmpty($validities);
1836
1837
        $validities = $this->manager->validate_setting_values(array( 'unknown' => 'X' ), array( 'validate_existence' => false ));
1838
        $this->assertEmpty($validities);
1839
1840
        $validities = $this->manager->validate_setting_values(array( 'unknown' => 'X' ), array( 'validate_existence' => true ));
1841
        $this->assertNotEmpty($validities);
1842
        $this->assertArrayHasKey('unknown', $validities);
1843
        $error = $validities['unknown'];
1844
        $this->assertInstanceOf('WP_Error', $error);
1845
        $this->assertEquals('unrecognized', $error->get_error_code());
1846
1847
        $this->manager->get_setting('blogname')->capability = 'do_not_allow';
1848
        $validities = $this->manager->validate_setting_values(array( 'blogname' => 'X' ), array( 'validate_capability' => false ));
1849
        $this->assertArrayHasKey('blogname', $validities);
1850
        $this->assertTrue($validities['blogname']);
1851
        $validities = $this->manager->validate_setting_values(array( 'blogname' => 'X' ), array( 'validate_capability' => true ));
1852
        $this->assertArrayHasKey('blogname', $validities);
1853
        $error = $validities['blogname'];
1854
        $this->assertInstanceOf('WP_Error', $error);
1855
        $this->assertEquals('unauthorized', $error->get_error_code());
1856
    }
1857
1858
    /**
1859
     * Add a length constraint to a setting.
1860
     *
1861
     * Adds minimum-length error code if the length is less than 10.
1862
     *
1863
     * @param  WP_Error             $validity Validity.
1864
     * @param  mixed                $value    Value.
1865
     * @param  WP_Customize_Setting $setting  Setting.
1866
     * @return WP_Error Validity.
1867
     */
1868
    function late_validate_length( $validity, $value, $setting ) 
1869
    {
1870
        $this->assertInstanceOf('WP_Customize_Setting', $setting);
1871
        if (strlen($value) < 10 ) {
1872
            $validity->add('minlength', '');
1873
        }
1874
        return $validity;
1875
    }
1876
1877
    /**
1878
     * Test the WP_Customize_Manager::validate_setting_values() method to make sure that the validation and sanitization are done in the right order.
1879
     *
1880
     * @ticket 37247
1881
     */
1882
    function test_validate_setting_values_validation_sanitization_order() 
1883
    {
1884
        wp_set_current_user(self::$admin_user_id);
1885
        $setting = $this->manager->add_setting(
1886
            'numeric', array(
1887
            'validate_callback' => array( $this, 'filter_customize_validate_numeric' ),
1888
            'sanitize_callback' => array( $this, 'filter_customize_sanitize_numeric' ),
1889
            ) 
1890
        );
1891
        $post_value = '42';
1892
        $this->manager->set_post_value('numeric', $post_value);
1893
        $validities = $this->manager->validate_setting_values($this->manager->unsanitized_post_values());
1894
        $this->assertCount(1, $validities);
1895
        $this->assertEquals(array( 'numeric' => true ), $validities);
1896
    }
1897
1898
    /**
1899
     * Test WP_Customize_Manager::prepare_setting_validity_for_js().
1900
     *
1901
     * @see WP_Customize_Manager::prepare_setting_validity_for_js()
1902
     */
1903
    function test_prepare_setting_validity_for_js() 
1904
    {
1905
        $this->assertTrue($this->manager->prepare_setting_validity_for_js(true));
1906
        $error = new WP_Error();
1907
        $error->add('bad_letter', 'Bad letter', 'A');
1908
        $error->add('bad_letter', 'Bad letra', 123);
1909
        $error->add('bad_number', 'Bad number', array( 'number' => 123 ));
1910
        $validity = $this->manager->prepare_setting_validity_for_js($error);
1911
        $this->assertInternalType('array', $validity);
1912
        foreach ( $error->errors as $code => $messages ) {
1913
            $this->assertArrayHasKey($code, $validity);
1914
            $this->assertInternalType('array', $validity[ $code ]);
1915
            $this->assertEquals(join(' ', $messages), $validity[ $code ]['message']);
1916
            $this->assertArrayHasKey('data', $validity[ $code ]);
1917
            $this->assertEquals($validity[ $code ]['data'], $error->get_error_data($code));
1918
        }
1919
        $this->assertArrayHasKey('number', $validity['bad_number']['data']);
1920
        $this->assertEquals(123, $validity['bad_number']['data']['number']);
1921
    }
1922
1923
    /**
1924
     * Test WP_Customize_Manager::set_post_value().
1925
     *
1926
     * @see WP_Customize_Manager::set_post_value()
1927
     */
1928
    function test_set_post_value() 
1929
    {
1930
        wp_set_current_user(self::$admin_user_id);
1931
        $this->manager->add_setting(
1932
            'foo', array(
1933
            'sanitize_callback' => array( $this, 'sanitize_foo_for_test_set_post_value' ),
1934
            ) 
1935
        );
1936
        $setting = $this->manager->get_setting('foo');
1937
1938
        $this->assertEmpty($this->captured_customize_post_value_set_actions);
1939
        add_action('customize_post_value_set', array( $this, 'capture_customize_post_value_set_actions' ), 10, 3);
1940
        add_action('customize_post_value_set_foo', array( $this, 'capture_customize_post_value_set_actions' ), 10, 2);
1941
        $this->manager->set_post_value($setting->id, '123abc');
1942
        $this->assertCount(2, $this->captured_customize_post_value_set_actions);
1943
        $this->assertEquals('customize_post_value_set_foo', $this->captured_customize_post_value_set_actions[0]['action']);
1944
        $this->assertEquals('customize_post_value_set', $this->captured_customize_post_value_set_actions[1]['action']);
1945
        $this->assertEquals(array( '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[0]['args']);
1946
        $this->assertEquals(array( $setting->id, '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[1]['args']);
1947
1948
        $unsanitized = $this->manager->unsanitized_post_values();
1949
        $this->assertArrayHasKey($setting->id, $unsanitized);
1950
1951
        $this->assertEquals('123abc', $unsanitized[ $setting->id ]);
1952
        $this->assertEquals(123, $setting->post_value());
1953
    }
1954
1955
    /**
1956
     * Sanitize a value for Tests_WP_Customize_Manager::test_set_post_value().
1957
     *
1958
     * @see Tests_WP_Customize_Manager::test_set_post_value()
1959
     *
1960
     * @param  mixed $value Value.
1961
     * @return int Value.
1962
     */
1963
    function sanitize_foo_for_test_set_post_value( $value ) 
1964
    {
1965
        return intval($value);
1966
    }
1967
1968
    /**
1969
     * Store data coming from customize_post_value_set action calls.
1970
     *
1971
     * @see Tests_WP_Customize_Manager::capture_customize_post_value_set_actions()
1972
     * @var array
1973
     */
1974
    protected $captured_customize_post_value_set_actions = array();
1975
1976
    /**
1977
     * Capture the actions fired when calling WP_Customize_Manager::set_post_value().
1978
     *
1979
     * @see Tests_WP_Customize_Manager::test_set_post_value()
1980
     */
1981
    function capture_customize_post_value_set_actions() 
1982
    {
1983
        $action = current_action();
1984
        $args = func_get_args();
1985
        $this->captured_customize_post_value_set_actions[] = compact('action', 'args');
1986
    }
1987
1988
    /**
1989
     * Test the WP_Customize_Manager::add_dynamic_settings() method.
1990
     *
1991
     * @ticket 30936
1992
     */
1993
    function test_add_dynamic_settings() 
1994
    {
1995
        $manager = $this->manager;
1996
        $setting_ids = array( 'foo', 'bar' );
1997
        $manager->add_setting('foo', array( 'default' => 'foo_default' ));
1998
        $this->assertEmpty($manager->get_setting('bar'), 'Expected there to not be a bar setting up front.');
1999
        $manager->add_dynamic_settings($setting_ids);
2000
        $this->assertEmpty($manager->get_setting('bar'), 'Expected the bar setting to remain absent since filters not added.');
2001
2002
        $this->action_customize_register_for_dynamic_settings();
2003
        $manager->add_dynamic_settings($setting_ids);
2004
        $this->assertNotEmpty($manager->get_setting('bar'), 'Expected bar setting to be created since filters were added.');
2005
        $this->assertEquals('foo_default', $manager->get_setting('foo')->default, 'Expected static foo setting to not get overridden by dynamic setting.');
2006
        $this->assertEquals('dynamic_bar_default', $manager->get_setting('bar')->default, 'Expected dynamic setting bar to have default providd by filter.');
2007
    }
2008
2009
    /**
2010
     * Test WP_Customize_Manager::has_published_pages().
2011
     *
2012
     * @ticket 38013
2013
     * @covers WP_Customize_Manager::has_published_pages()
2014
     */
2015
    function test_has_published_pages() 
2016
    {
2017
        foreach ( get_pages() as $page ) {
2018
            wp_delete_post($page->ID, true);
2019
        }
2020
        $this->assertFalse($this->manager->has_published_pages());
2021
2022
        $this->factory()->post->create(array( 'post_type' => 'page', 'post_status' => 'private' ));
2023
        $this->assertFalse($this->manager->has_published_pages());
2024
2025
        $this->factory()->post->create(array( 'post_type' => 'page', 'post_status' => 'publish' ));
2026
        $this->assertTrue($this->manager->has_published_pages());
2027
    }
2028
2029
    /**
2030
     * Ensure that page stubs created via nav menus will cause has_published_pages to return true.
2031
     *
2032
     * @ticket 38013
2033
     * @covers WP_Customize_Manager::has_published_pages()
2034
     */
2035
    function test_has_published_pages_when_nav_menus_created_posts() 
2036
    {
2037
        foreach ( get_pages() as $page ) {
2038
            wp_delete_post($page->ID, true);
2039
        }
2040
        $this->assertFalse($this->manager->has_published_pages());
2041
2042
        wp_set_current_user(self::$admin_user_id);
2043
        $this->manager->nav_menus->customize_register();
2044
        $setting_id = 'nav_menus_created_posts';
2045
        $setting = $this->manager->get_setting($setting_id);
2046
        $this->assertInstanceOf('WP_Customize_Filter_Setting', $setting);
2047
        $auto_draft_page = $this->factory()->post->create(array( 'post_type' => 'page', 'post_status' => 'auto-draft' ));
2048
        $this->manager->set_post_value($setting_id, array( $auto_draft_page ));
2049
        $setting->preview();
2050
        $this->assertTrue($this->manager->has_published_pages());
2051
    }
2052
2053
    /**
2054
     * Test the WP_Customize_Manager::register_dynamic_settings() method.
2055
     *
2056
     * This is similar to test_add_dynamic_settings, except the settings are passed via $_POST['customized'].
2057
     *
2058
     * @ticket 30936
2059
     */
2060
    function test_register_dynamic_settings() 
2061
    {
2062
        wp_set_current_user(self::$admin_user_id);
2063
        $posted_settings = array(
2064
         'foo' => 'OOF',
2065
         'bar' => 'RAB',
2066
        );
2067
        $_POST['customized'] = wp_slash(wp_json_encode($posted_settings));
2068
2069
        add_action('customize_register', array( $this, 'action_customize_register_for_dynamic_settings' ));
2070
2071
        $manager = $this->manager;
2072
        $manager->add_setting('foo', array( 'default' => 'foo_default' ));
2073
2074
        $this->assertEmpty($manager->get_setting('bar'), 'Expected dynamic setting "bar" to not be registered.');
2075
        do_action('customize_register', $manager);
2076
        $this->assertNotEmpty($manager->get_setting('bar'), 'Expected dynamic setting "bar" to be automatically registered after customize_register action.');
2077
        $this->assertEmpty($manager->get_setting('baz'), 'Expected unrecognized dynamic setting "baz" to remain unregistered.');
2078
    }
2079
2080
    /**
2081
     * In lieu of closures, callback for customize_register action added in test_register_dynamic_settings().
2082
     */
2083
    function action_customize_register_for_dynamic_settings() 
2084
    {
2085
        add_filter('customize_dynamic_setting_args', array( $this, 'filter_customize_dynamic_setting_args_for_test_dynamic_settings' ), 10, 2);
2086
        add_filter('customize_dynamic_setting_class', array( $this, 'filter_customize_dynamic_setting_class_for_test_dynamic_settings' ), 10, 3);
2087
    }
2088
2089
    /**
2090
     * In lieu of closures, callback for customize_dynamic_setting_args filter added for test_register_dynamic_settings().
2091
     *
2092
     * @param  array  $setting_args Setting args.
2093
     * @param  string $setting_id   Setting ID.
2094
     * @return array
2095
     */
2096
    function filter_customize_dynamic_setting_args_for_test_dynamic_settings( $setting_args, $setting_id ) 
2097
    {
2098
        $this->assertInternalType('string', $setting_id);
2099
        if (in_array($setting_id, array( 'foo', 'bar' )) ) {
2100
            $setting_args = array( 'default' => "dynamic_{$setting_id}_default" );
2101
        }
2102
        return $setting_args;
2103
    }
2104
2105
    /**
2106
     * In lieu of closures, callback for customize_dynamic_setting_class filter added for test_register_dynamic_settings().
2107
     *
2108
     * @param  string $setting_class Setting class.
2109
     * @param  string $setting_id    Setting ID.
2110
     * @param  array  $setting_args  Setting args.
2111
     * @return string
2112
     */
2113
    function filter_customize_dynamic_setting_class_for_test_dynamic_settings( $setting_class, $setting_id, $setting_args ) 
2114
    {
2115
        $this->assertEquals('WP_Customize_Setting', $setting_class);
2116
        $this->assertInternalType('string', $setting_id);
2117
        $this->assertInternalType('array', $setting_args);
2118
        return $setting_class;
2119
    }
2120
2121
    /**
2122
     * Test is_ios() method.
2123
     *
2124
     * @see WP_Customize_Manager::is_ios()
2125
     */
2126
    function test_is_ios() 
2127
    {
2128
        $this->markTestSkipped('WP_Customize_Manager::is_ios() cannot be tested because it uses wp_is_mobile() which contains a static var.');
2129
    }
2130
2131
    /**
2132
     * Test get_document_title_template() method.
2133
     *
2134
     * @see WP_Customize_Manager::get_document_title_template()
2135
     */
2136
    function test_get_document_title_template() 
2137
    {
2138
        $tpl = $this->manager->get_document_title_template();
2139
        $this->assertContains('%s', $tpl);
2140
    }
2141
2142
    /**
2143
     * Test get_preview_url()/set_preview_url methods.
2144
     *
2145
     * @see WP_Customize_Manager::get_preview_url()
2146
     * @see WP_Customize_Manager::set_preview_url()
2147
     */
2148
    function test_preview_url() 
2149
    {
2150
        $this->assertEquals(home_url('/'), $this->manager->get_preview_url());
2151
        $preview_url = home_url('/foo/bar/baz/');
2152
        $this->manager->set_preview_url($preview_url);
2153
        $this->assertEquals($preview_url, $this->manager->get_preview_url());
2154
        $this->manager->set_preview_url('http://illegalsite.example.com/food/');
2155
        $this->assertEquals(home_url('/'), $this->manager->get_preview_url());
2156
    }
2157
2158
    /**
2159
     * Test get_return_url()/set_return_url() methods.
2160
     *
2161
     * @see WP_Customize_Manager::get_return_url()
2162
     * @see WP_Customize_Manager::set_return_url()
2163
     */
2164
    function test_return_url() 
2165
    {
2166
        wp_set_current_user(self::factory()->user->create(array( 'role' => 'author' )));
2167
        $this->assertEquals(home_url('/'), $this->manager->get_return_url());
2168
2169
        wp_set_current_user(self::$admin_user_id);
2170
        $this->assertTrue(current_user_can('edit_theme_options'));
2171
        $this->assertEquals(home_url('/'), $this->manager->get_return_url());
2172
2173
        $preview_url = home_url('/foo/');
2174
        $this->manager->set_preview_url($preview_url);
2175
        $this->assertEquals($preview_url, $this->manager->get_return_url());
2176
2177
        $_SERVER['HTTP_REFERER'] = wp_slash(admin_url('customize.php'));
2178
        $this->assertEquals($preview_url, $this->manager->get_return_url());
2179
2180
        // See #35355.
2181
        $_SERVER['HTTP_REFERER'] = wp_slash(admin_url('wp-login.php'));
2182
        $this->assertEquals($preview_url, $this->manager->get_return_url());
2183
2184
        $url = home_url('/referred/');
2185
        $_SERVER['HTTP_REFERER'] = wp_slash($url);
2186
        $this->assertEquals($url, $this->manager->get_return_url());
2187
2188
        $url = 'http://badreferer.example.com/';
2189
        $_SERVER['HTTP_REFERER'] = wp_slash($url);
2190
        $this->assertNotEquals($url, $this->manager->get_return_url());
2191
        $this->assertEquals($preview_url, $this->manager->get_return_url());
2192
2193
        $this->manager->set_return_url(admin_url('edit.php?trashed=1'));
2194
        $this->assertEquals(admin_url('edit.php'), $this->manager->get_return_url());
2195
    }
2196
2197
    /**
2198
     * Test get_autofocus()/set_autofocus() methods.
2199
     *
2200
     * @see WP_Customize_Manager::get_autofocus()
2201
     * @see WP_Customize_Manager::set_autofocus()
2202
     */
2203
    function test_autofocus() 
2204
    {
2205
        $this->assertEmpty($this->manager->get_autofocus());
2206
2207
        $this->manager->set_autofocus(array( 'unrecognized' => 'food' ));
2208
        $this->assertEmpty($this->manager->get_autofocus());
2209
2210
        $autofocus = array( 'control' => 'blogname' );
2211
        $this->manager->set_autofocus($autofocus);
2212
        $this->assertEquals($autofocus, $this->manager->get_autofocus());
2213
2214
        $autofocus = array( 'section' => 'colors' );
2215
        $this->manager->set_autofocus($autofocus);
2216
        $this->assertEquals($autofocus, $this->manager->get_autofocus());
2217
2218
        $autofocus = array( 'panel' => 'widgets' );
2219
        $this->manager->set_autofocus($autofocus);
2220
        $this->assertEquals($autofocus, $this->manager->get_autofocus());
2221
2222
        $autofocus = array( 'control' => array( 'blogname', 'blogdescription' ) );
2223
        $this->manager->set_autofocus($autofocus);
2224
        $this->assertEmpty($this->manager->get_autofocus());
2225
    }
2226
2227
    /**
2228
     * Test get_nonces() method.
2229
     *
2230
     * @see WP_Customize_Manager::get_nonces()
2231
     */
2232
    function test_nonces() 
2233
    {
2234
        $nonces = $this->manager->get_nonces();
2235
        $this->assertInternalType('array', $nonces);
2236
        $this->assertArrayHasKey('save', $nonces);
2237
        $this->assertArrayHasKey('preview', $nonces);
2238
2239
        add_filter('customize_refresh_nonces', array( $this, 'filter_customize_refresh_nonces' ), 10, 2);
2240
        $nonces = $this->manager->get_nonces();
2241
        $this->assertArrayHasKey('foo', $nonces);
2242
        $this->assertEquals(wp_create_nonce('foo'), $nonces['foo']);
2243
    }
2244
2245
    /**
2246
     * Filter for customize_refresh_nonces.
2247
     *
2248
     * @param  array                $nonces  Nonces.
2249
     * @param  WP_Customize_Manager $manager Manager.
2250
     * @return array Nonces.
2251
     */
2252
    function filter_customize_refresh_nonces( $nonces, $manager ) 
2253
    {
2254
        $this->assertInstanceOf('WP_Customize_Manager', $manager);
2255
        $nonces['foo'] = wp_create_nonce('foo');
2256
        return $nonces;
2257
    }
2258
2259
    /**
2260
     * Test customize_pane_settings() method.
2261
     *
2262
     * @see WP_Customize_Manager::customize_pane_settings()
2263
     */
2264
    function test_customize_pane_settings() 
2265
    {
2266
        wp_set_current_user(self::$admin_user_id);
2267
        $this->manager->register_controls();
2268
        $this->manager->prepare_controls();
2269
        $autofocus = array( 'control' => 'blogname' );
2270
        $this->manager->set_autofocus($autofocus);
2271
2272
        ob_start();
2273
        $this->manager->customize_pane_settings();
2274
        $content = ob_get_clean();
2275
2276
        $this->assertContains('var _wpCustomizeSettings =', $content);
2277
        $this->assertContains('"blogname"', $content);
2278
        $this->assertContains('"type":"option"', $content);
2279
        $this->assertContains('_wpCustomizeSettings.controls', $content);
2280
        $this->assertContains('_wpCustomizeSettings.settings', $content);
2281
        $this->assertContains('</script>', $content);
2282
2283
        $this->assertNotEmpty(preg_match('#var _wpCustomizeSettings\s*=\s*({.*?});\s*\n#', $content, $matches));
2284
        $json = $matches[1];
2285
        $data = json_decode($json, true);
2286
        $this->assertNotEmpty($data);
2287
2288
        $this->assertEqualSets(array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts' ), array_keys($data));
2289
        $this->assertEquals($autofocus, $data['autofocus']);
2290
        $this->assertArrayHasKey('save', $data['nonce']);
2291
        $this->assertArrayHasKey('preview', $data['nonce']);
2292
    }
2293
2294
    /**
2295
     * Test remove_frameless_preview_messenger_channel.
2296
     *
2297
     * @ticket 38867
2298
     * @covers WP_Customize_Manager::remove_frameless_preview_messenger_channel()
2299
     */
2300
    function test_remove_frameless_preview_messenger_channel() 
2301
    {
2302
        wp_set_current_user(self::$admin_user_id);
2303
        $manager = new WP_Customize_Manager(array( 'messenger_channel' => null ));
2304
        ob_start();
2305
        $manager->remove_frameless_preview_messenger_channel();
2306
        $output = ob_get_clean();
2307
        $this->assertEmpty($output);
2308
2309
        $manager = new WP_Customize_Manager(array( 'messenger_channel' => 'preview-0' ));
2310
        ob_start();
2311
        $manager->remove_frameless_preview_messenger_channel();
2312
        $output = ob_get_clean();
2313
        $this->assertContains('<script>', $output);
2314
    }
2315
2316
    /**
2317
     * Test customize_preview_settings() method.
2318
     *
2319
     * @see WP_Customize_Manager::customize_preview_settings()
2320
     */
2321
    function test_customize_preview_settings() 
2322
    {
2323
        wp_set_current_user(self::$admin_user_id);
2324
        $this->manager->register_controls();
2325
        $this->manager->prepare_controls();
2326
        $this->manager->set_post_value('foo', 'bar');
2327
        $_POST['customize_messenger_channel'] = 'preview-0';
2328
2329
        ob_start();
2330
        $this->manager->customize_preview_settings();
2331
        $content = ob_get_clean();
2332
2333
        $this->assertEquals(1, preg_match('/var _wpCustomizeSettings = ({.+});/', $content, $matches));
2334
        $settings = json_decode($matches[1], true);
2335
2336
        $this->assertArrayHasKey('theme', $settings);
2337
        $this->assertArrayHasKey('url', $settings);
2338
        $this->assertArrayHasKey('channel', $settings);
2339
        $this->assertArrayHasKey('activePanels', $settings);
2340
        $this->assertArrayHasKey('activeSections', $settings);
2341
        $this->assertArrayHasKey('activeControls', $settings);
2342
        $this->assertArrayHasKey('settingValidities', $settings);
2343
        $this->assertArrayHasKey('nonce', $settings);
2344
        $this->assertArrayHasKey('_dirty', $settings);
2345
        $this->assertArrayHasKey('timeouts', $settings);
2346
        $this->assertArrayHasKey('changeset', $settings);
2347
2348
        $this->assertArrayHasKey('preview', $settings['nonce']);
2349
    }
2350
2351
    /**
2352
     * @ticket 33552
2353
     */
2354
    function test_customize_loaded_components_filter() 
2355
    {
2356
        $manager = new WP_Customize_Manager();
2357
        $this->assertInstanceOf('WP_Customize_Widgets', $manager->widgets);
2358
        $this->assertInstanceOf('WP_Customize_Nav_Menus', $manager->nav_menus);
2359
2360
        add_filter('customize_loaded_components', array( $this, 'return_array_containing_widgets' ), 10, 2);
2361
        $manager = new WP_Customize_Manager();
2362
        $this->assertInstanceOf('WP_Customize_Widgets', $manager->widgets);
2363
        $this->assertEmpty($manager->nav_menus);
2364
        remove_all_filters('customize_loaded_components');
2365
2366
        add_filter('customize_loaded_components', array( $this, 'return_array_containing_nav_menus' ), 10, 2);
2367
        $manager = new WP_Customize_Manager();
2368
        $this->assertInstanceOf('WP_Customize_Nav_Menus', $manager->nav_menus);
2369
        $this->assertEmpty($manager->widgets);
2370
        remove_all_filters('customize_loaded_components');
2371
2372
        add_filter('customize_loaded_components', '__return_empty_array');
2373
        $manager = new WP_Customize_Manager();
2374
        $this->assertEmpty($manager->widgets);
2375
        $this->assertEmpty($manager->nav_menus);
2376
        remove_all_filters('customize_loaded_components');
2377
    }
2378
2379
    /**
2380
     * @see Tests_WP_Customize_Manager::test_customize_loaded_components_filter()
2381
     *
2382
     * @param array                $components        Components.
2383
     * @param WP_Customize_Manager $customize_manager Manager.
2384
     *
2385
     * @return array Components.
2386
     */
2387 View Code Duplication
    function return_array_containing_widgets( $components, $customize_manager ) 
2388
    {
2389
        $this->assertInternalType('array', $components);
2390
        $this->assertContains('widgets', $components);
2391
        $this->assertContains('nav_menus', $components);
2392
        $this->assertInternalType('array', $components);
2393
        $this->assertInstanceOf('WP_Customize_Manager', $customize_manager);
2394
        return array( 'widgets' );
2395
    }
2396
2397
    /**
2398
     * @see Tests_WP_Customize_Manager::test_customize_loaded_components_filter()
2399
     *
2400
     * @param array                $components        Components.
2401
     * @param WP_Customize_Manager $customize_manager Manager.
2402
     *
2403
     * @return array Components.
2404
     */
2405 View Code Duplication
    function return_array_containing_nav_menus( $components, $customize_manager ) 
2406
    {
2407
        $this->assertInternalType('array', $components);
2408
        $this->assertContains('widgets', $components);
2409
        $this->assertContains('nav_menus', $components);
2410
        $this->assertInternalType('array', $components);
2411
        $this->assertInstanceOf('WP_Customize_Manager', $customize_manager);
2412
        return array( 'nav_menus' );
2413
    }
2414
2415
    /**
2416
     * @ticket 30225
2417
     * @ticket 34594
2418
     */
2419
    function test_prepare_controls_stable_sorting() 
2420
    {
2421
        $manager = new WP_Customize_Manager();
2422
        $manager->register_controls();
2423
        $section_id = 'foo-section';
2424
        wp_set_current_user(self::$admin_user_id);
2425
        $manager->add_section(
2426
            $section_id, array(
2427
            'title'      => 'Section',
2428
            'priority'   => 1,
2429
            ) 
2430
        );
2431
2432
        $added_control_ids = array();
2433
        $count = 9;
2434
        for ( $i = 0; $i < $count; $i += 1 ) {
2435
            $id = 'sort-test-' . $i;
2436
            $added_control_ids[] = $id;
2437
            $manager->add_setting($id);
2438
            $control = new WP_Customize_Control(
2439
                $manager, $id, array(
2440
                'section' => $section_id,
2441
                'priority' => 1,
2442
                'setting' => $id,
2443
                ) 
2444
            );
2445
            $manager->add_control($control);
2446
        }
2447
2448
        $manager->prepare_controls();
2449
2450
        $sorted_control_ids = wp_list_pluck($manager->get_section($section_id)->controls, 'id');
2451
        $this->assertEquals($added_control_ids, $sorted_control_ids);
2452
    }
2453
2454
    /**
2455
     * @ticket 34596
2456
     */
2457 View Code Duplication
    function test_add_section_return_instance() 
2458
    {
2459
        $manager = new WP_Customize_Manager();
2460
        wp_set_current_user(self::$admin_user_id);
2461
2462
        $section_id = 'foo-section';
2463
        $result_section = $manager->add_section(
2464
            $section_id, array(
2465
            'title'    => 'Section',
2466
            'priority' => 1,
2467
            ) 
2468
        );
2469
2470
        $this->assertInstanceOf('WP_Customize_Section', $result_section);
2471
        $this->assertEquals($section_id, $result_section->id);
2472
2473
        $section = new WP_Customize_Section(
2474
            $manager, $section_id, array(
2475
            'title'    => 'Section 2',
2476
            'priority' => 2,
2477
            ) 
2478
        );
2479
        $result_section = $manager->add_section($section);
2480
2481
        $this->assertInstanceOf('WP_Customize_Section', $result_section);
2482
        $this->assertEquals($section_id, $result_section->id);
2483
        $this->assertEquals($section, $result_section);
2484
    }
2485
2486
    /**
2487
     * @ticket 34596
2488
     */
2489
    function test_add_setting_return_instance() 
2490
    {
2491
        $manager = new WP_Customize_Manager();
2492
        wp_set_current_user(self::$admin_user_id);
2493
2494
        $setting_id = 'foo-setting';
2495
        $result_setting = $manager->add_setting($setting_id);
2496
2497
        $this->assertInstanceOf('WP_Customize_Setting', $result_setting);
2498
        $this->assertEquals($setting_id, $result_setting->id);
2499
2500
        $setting = new WP_Customize_Setting($manager, $setting_id);
2501
        $result_setting = $manager->add_setting($setting);
2502
2503
        $this->assertInstanceOf('WP_Customize_Setting', $result_setting);
2504
        $this->assertEquals($setting, $result_setting);
2505
        $this->assertEquals($setting_id, $result_setting->id);
2506
    }
2507
2508
    /**
2509
     * @ticket 34597
2510
     */
2511
    function test_add_setting_honoring_dynamic() 
2512
    {
2513
        $manager = new WP_Customize_Manager();
2514
2515
        $setting_id = 'dynamic';
2516
        $setting = $manager->add_setting($setting_id);
2517
        $this->assertEquals('WP_Customize_Setting', get_class($setting));
2518
        $this->assertObjectNotHasAttribute('custom', $setting);
2519
        $manager->remove_setting($setting_id);
2520
2521
        add_filter('customize_dynamic_setting_class', array( $this, 'return_dynamic_customize_setting_class' ), 10, 3);
2522
        add_filter('customize_dynamic_setting_args', array( $this, 'return_dynamic_customize_setting_args' ), 10, 2);
2523
        $setting = $manager->add_setting($setting_id);
2524
        $this->assertEquals('Test_Dynamic_Customize_Setting', get_class($setting));
2525
        $this->assertObjectHasAttribute('custom', $setting);
2526
        $this->assertEquals('foo', $setting->custom);
2527
    }
2528
2529
    /**
2530
     * Return 'Test_Dynamic_Customize_Setting' in 'customize_dynamic_setting_class.
2531
     *
2532
     * @param  string $class Setting class.
2533
     * @param  array  $args  Setting args.
2534
     * @param  string $id    Setting ID.
2535
     * @return string       Setting class.
2536
     */
2537
    function return_dynamic_customize_setting_class( $class, $id, $args ) 
2538
    {
2539
        unset($args);
2540
        if (0 === strpos($id, 'dynamic') ) {
2541
            $class = 'Test_Dynamic_Customize_Setting';
2542
        }
2543
        return $class;
2544
    }
2545
2546
    /**
2547
     * Return 'Test_Dynamic_Customize_Setting' in 'customize_dynamic_setting_class.
2548
     *
2549
     * @param  array  $args Setting args.
2550
     * @param  string $id   Setting ID.
2551
     * @return string      Setting args.
2552
     */
2553
    function return_dynamic_customize_setting_args( $args, $id ) 
2554
    {
2555
        if (0 === strpos($id, 'dynamic') ) {
2556
            $args['custom'] = 'foo';
2557
        }
2558
        return $args;
2559
    }
2560
2561
    /**
2562
     * @ticket 34596
2563
     */
2564 View Code Duplication
    function test_add_panel_return_instance() 
2565
    {
2566
        $manager = new WP_Customize_Manager();
2567
        wp_set_current_user(self::$admin_user_id);
2568
2569
        $panel_id = 'foo-panel';
2570
        $result_panel = $manager->add_panel(
2571
            $panel_id, array(
2572
            'title'    => 'Test Panel',
2573
            'priority' => 2,
2574
            ) 
2575
        );
2576
2577
        $this->assertInstanceOf('WP_Customize_Panel', $result_panel);
2578
        $this->assertEquals($panel_id, $result_panel->id);
2579
2580
        $panel = new WP_Customize_Panel(
2581
            $manager, $panel_id, array(
2582
            'title' => 'Test Panel 2',
2583
            ) 
2584
        );
2585
        $result_panel = $manager->add_panel($panel);
2586
2587
        $this->assertInstanceOf('WP_Customize_Panel', $result_panel);
2588
        $this->assertEquals($panel, $result_panel);
2589
        $this->assertEquals($panel_id, $result_panel->id);
2590
    }
2591
2592
    /**
2593
     * @ticket 34596
2594
     */
2595
    function test_add_control_return_instance() 
2596
    {
2597
        $manager = new WP_Customize_Manager();
2598
        $section_id = 'foo-section';
2599
        wp_set_current_user(self::$admin_user_id);
2600
        $manager->add_section(
2601
            $section_id, array(
2602
            'title'    => 'Section',
2603
            'priority' => 1,
2604
            ) 
2605
        );
2606
2607
        $control_id = 'foo-control';
2608
        $manager->add_setting($control_id);
2609
2610
        $result_control = $manager->add_control(
2611
            $control_id, array(
2612
            'section'  => $section_id,
2613
            'priority' => 1,
2614
            'setting'  => $control_id,
2615
            ) 
2616
        );
2617
        $this->assertInstanceOf('WP_Customize_Control', $result_control);
2618
        $this->assertEquals($control_id, $result_control->id);
2619
2620
        $control = new WP_Customize_Control(
2621
            $manager, $control_id, array(
2622
            'section'  => $section_id,
2623
            'priority' => 1,
2624
            'setting'  => $control_id,
2625
            ) 
2626
        );
2627
        $result_control = $manager->add_control($control);
2628
2629
        $this->assertInstanceOf('WP_Customize_Control', $result_control);
2630
        $this->assertEquals($control, $result_control);
2631
        $this->assertEquals($control_id, $result_control->id);
2632
    }
2633
2634
2635
    /**
2636
     * Testing the return values both with and without filter.
2637
     *
2638
     * @ticket 31195
2639
     */
2640
    function test_get_previewable_devices() 
2641
    {
2642
2643
        // Setup the instance.
2644
        $manager = new WP_Customize_Manager();
2645
2646
        // The default devices list.
2647
        $default_devices = array(
2648
         'desktop' => array(
2649
          'label'   => __('Enter desktop preview mode'),
2650
          'default' => true,
2651
         ),
2652
         'tablet'  => array(
2653
          'label' => __('Enter tablet preview mode'),
2654
         ),
2655
         'mobile'  => array(
2656
          'label' => __('Enter mobile preview mode'),
2657
         ),
2658
        );
2659
2660
        // Control test.
2661
        $devices = $manager->get_previewable_devices();
2662
        $this->assertSame($default_devices, $devices);
2663
2664
        // Adding the filter.
2665
        add_filter('customize_previewable_devices', array( $this, 'filter_customize_previewable_devices' ));
2666
        $devices = $manager->get_previewable_devices();
2667
        $this->assertSame($this->filtered_device_list(), $devices);
2668
2669
        // Clean up.
2670
        remove_filter('customize_previewable_devices', array( $this, 'filter_customize_previewable_devices' ));
2671
    }
2672
2673
    /**
2674
     * Helper method for test_get_previewable_devices.
2675
     *
2676
     * @return array
2677
     */
2678
    function filtered_device_list() 
2679
    {
2680
        return array(
2681
         'custom-device' => array(
2682
          'label' => __('Enter custom-device preview mode'),
2683
          'default' => true,
2684
         ),
2685
        );
2686
    }
2687
2688
    /**
2689
     * Callback for the customize_previewable_devices filter.
2690
     *
2691
     * @param array $devices The list of devices.
2692
     *
2693
     * @return array
2694
     */
2695
    function filter_customize_previewable_devices( $devices ) 
2696
    {
2697
        return $this->filtered_device_list();
2698
    }
2699
2700
    /**
2701
     * @ticket 37128
2702
     */
2703
    function test_prepare_controls_wp_list_sort_controls() 
2704
    {
2705
        wp_set_current_user(self::$admin_user_id);
2706
2707
        $controls = array( 'foo' => 2, 'bar' => 4, 'foobar' => 3, 'key' => 1 );
2708
        $controls_sorted = array( 'key', 'foo', 'foobar', 'bar' );
2709
2710
        $this->manager->add_section('foosection', array());
2711
2712
        foreach ( $controls as $control_id => $priority ) {
2713
            $this->manager->add_setting($control_id);
2714
            $this->manager->add_control(
2715
                $control_id, array(
2716
                'priority' => $priority,
2717
                'section'  => 'foosection',
2718
                ) 
2719
            );
2720
        }
2721
2722
        $this->manager->prepare_controls();
2723
2724
        $result = $this->manager->controls();
2725
        $this->assertEquals($controls_sorted, array_keys($result));
2726
    }
2727
2728
    /**
2729
     * @ticket 37128
2730
     */
2731 View Code Duplication
    function test_prepare_controls_wp_list_sort_sections() 
2732
    {
2733
        wp_set_current_user(self::$admin_user_id);
2734
2735
        $sections = array( 'foo' => 2, 'bar' => 4, 'foobar' => 3, 'key' => 1 );
2736
        $sections_sorted = array( 'key', 'foo', 'foobar', 'bar' );
2737
2738
        foreach ( $sections as $section_id => $priority ) {
2739
            $this->manager->add_section(
2740
                $section_id, array(
2741
                'priority' => $priority,
2742
                ) 
2743
            );
2744
        }
2745
2746
        $this->manager->prepare_controls();
2747
2748
        $result = $this->manager->sections();
2749
        $this->assertEquals($sections_sorted, array_keys($result));
2750
    }
2751
2752
    /**
2753
     * @ticket 37128
2754
     */
2755 View Code Duplication
    function test_prepare_controls_wp_list_sort_panels() 
2756
    {
2757
        wp_set_current_user(self::$admin_user_id);
2758
2759
        $panels = array( 'foo' => 2, 'bar' => 4, 'foobar' => 3, 'key' => 1 );
2760
        $panels_sorted = array( 'key', 'foo', 'foobar', 'bar' );
2761
2762
        foreach ( $panels as $panel_id => $priority ) {
2763
            $this->manager->add_panel(
2764
                $panel_id, array(
2765
                'priority' => $priority,
2766
                ) 
2767
            );
2768
        }
2769
2770
        $this->manager->prepare_controls();
2771
2772
        $result = $this->manager->panels();
2773
        $this->assertEquals($panels_sorted, array_keys($result));
2774
    }
2775
}
2776
2777
require_once ABSPATH . WPINC . '/class-wp-customize-setting.php';
2778
2779
/**
2780
 * Class Test_Dynamic_Customize_Setting
2781
 *
2782
 * @see Tests_WP_Customize_Manager::test_add_setting_honoring_dynamic()
2783
 */
2784
class Test_Dynamic_Customize_Setting extends WP_Customize_Setting
2785
{
2786
    public $type = 'dynamic';
2787
    public $custom;
2788
}
2789
2790
/**
2791
 * Class Test_Setting_Without_Applying_Validate_Filter.
2792
 *
2793
 * @see Tests_WP_Customize_Manager::test_late_validate_setting_values()
2794
 */
2795
class Test_Setting_Without_Applying_Validate_Filter extends WP_Customize_Setting
2796
{
2797
2798
    /**
2799
     * Validates an input.
2800
     *
2801
     * @param  mixed $value Value to validate.
2802
     * @return true|WP_Error True if the input was validated, otherwise WP_Error.
2803
     */
2804
    public function validate( $value ) 
2805
    {
2806
        if (empty($value) ) {
2807
            return new WP_Error('empty_value', __('You must supply a value'));
2808
        }
2809
        return true;
2810
    }
2811
2812
}
2813