Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.

Commit 5ed04eb

Browse files
authored
Merge pull request #233 from xwp/feature/post-parent
Add control to manipulate the post parent
2 parents 0fd04c8 + ffdbe67 commit 5ed04eb

9 files changed

+164
-35
lines changed

js/customize-post-section.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@
272272
section.addStatusControl();
273273
section.addDateControl();
274274
}
275+
if ( postTypeObj.supports['page-attributes'] || postTypeObj.supports.parent ) {
276+
section.addParentControl();
277+
}
275278
if ( postTypeObj.supports.editor ) {
276279
section.addContentControl();
277280
}
@@ -471,6 +474,75 @@
471474
return control;
472475
},
473476

477+
/**
478+
* Add parent control.
479+
*
480+
* @returns {wp.customize.Control} Added control.
481+
*/
482+
addParentControl: function() {
483+
var section = this, control, setting = api( section.id ), controlId, params, postTypeObj;
484+
postTypeObj = api.Posts.data.postTypes[ section.params.post_type ];
485+
486+
controlId = section.id + '[post_parent]';
487+
params = {
488+
section: section.id,
489+
priority: 20,
490+
label: postTypeObj.labels.parent_item_colon ? postTypeObj.labels.parent_item_colon.replace( /:$/, '' ) : api.Posts.data.l10n.fieldParentLabel,
491+
active: true,
492+
settings: {
493+
'default': setting.id
494+
},
495+
field_type: 'select',
496+
setting_property: 'post_parent'
497+
};
498+
499+
if ( api.controlConstructor.object_selector ) {
500+
control = new api.controlConstructor.object_selector( controlId, {
501+
params: _.extend( params, {
502+
post_query_vars: {
503+
post_type: section.params.post_type,
504+
post_status: 'publish',
505+
post__not_in: [ section.params.post_id ],
506+
show_initial_dropdown: true,
507+
dropdown_args: {
508+
exclude_tree: section.params.post_id,
509+
sort_column: 'menu_order, post_title'
510+
},
511+
apply_dropdown_args_filters_post_id: section.params.post_id // Applies page_attributes_dropdown_pages_args filters.
512+
},
513+
show_add_buttons: false,
514+
select2_options: {
515+
multiple: false,
516+
allowClear: true,
517+
placeholder: postTypeObj.labels.search_items
518+
}
519+
} )
520+
} );
521+
} else {
522+
control = new api.controlConstructor.dynamic( controlId, {
523+
params: _.extend( params, {
524+
field_type: 'hidden',
525+
description: api.Posts.data.l10n.installCustomizeObjectSelector
526+
} )
527+
} );
528+
}
529+
530+
// Override preview trying to de-activate control not present in preview context.
531+
control.active.validate = function() {
532+
return true;
533+
};
534+
535+
// Register.
536+
section.postFieldControls.page_parent = control;
537+
api.control.add( control.id, control );
538+
539+
if ( control.notifications ) {
540+
control.notifications.add = section.addPostFieldControlNotification;
541+
control.notifications.setting_property = control.params.setting_property;
542+
}
543+
return control;
544+
},
545+
474546
/**
475547
* Add post date control.
476548
*

js/edit-post-preview-admin-featured-image.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
featuredImageId = parseInt( $( inputSelector ).val(), 10 );
1111

1212
if ( featuredImageId <= 0 ) {
13-
featuredImageId = '';
13+
featuredImageId = 0;
1414
}
1515

1616
settings[ settingId ] = featuredImageId;

js/edit-post-preview-admin.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ var EditPostPreviewAdmin = (function( $ ) {
2727
settings = {},
2828
postSettingValue,
2929
editor = tinymce.get( 'content' ),
30-
wasMobile;
30+
wasMobile,
31+
parentId;
3132

3233
event.preventDefault();
3334

@@ -44,15 +45,23 @@ var EditPostPreviewAdmin = (function( $ ) {
4445
// Override default close behavior.
4546
wp.customize.Loader.close = component.closeLoader;
4647

48+
parentId = $( '#parent_id' ).val();
49+
if ( ! parentId ) {
50+
parentId = 0;
51+
} else {
52+
parentId = parseInt( parentId, 10 );
53+
}
54+
4755
// Send the current input fields from the edit post page to the Customizer via sessionStorage.
4856
postSettingValue = {
4957
post_title: $( '#title' ).val(),
5058
post_name: $( '#post_name' ).val(),
59+
post_parent: parentId,
5160
post_content: editor && ! editor.isHidden() ? wp.editor.removep( editor.getContent() ) : $( '#content' ).val(),
5261
post_excerpt: $( '#excerpt' ).val(),
5362
comment_status: $( '#comment_status' ).prop( 'checked' ) ? 'open' : 'closed',
5463
ping_status: $( '#ping_status' ).prop( 'checked' ) ? 'open' : 'closed',
55-
post_author: $( '#post_author_override' ).val()
64+
post_author: parseInt( $( '#post_author_override' ).val(), 10 )
5665
};
5766
postSettingId = 'post[' + postType + '][' + postId + ']';
5867
settings[ postSettingId ] = postSettingValue;
@@ -66,6 +75,7 @@ var EditPostPreviewAdmin = (function( $ ) {
6675

6776
// Sync changes from the Customizer to the post input fields.
6877
wp.customize.Loader.messenger.bind( 'customize-post-settings-data', function( data ) {
78+
var settingParentId;
6979
if ( data[ postSettingId ] ) {
7080
$( '#title' ).val( data[ postSettingId ].post_title ).trigger( 'change' );
7181
if ( editor ) {
@@ -79,6 +89,8 @@ var EditPostPreviewAdmin = (function( $ ) {
7989
$( '#ping_status' ).prop( 'checked', 'open' === data[ postSettingId ].ping_status ).trigger( 'change' );
8090
$( '#post_author_override' ).val( data[ postSettingId ].post_author ).trigger( 'change' );
8191
$( '#post_name' ).val( data[ postSettingId ].post_name ).trigger( 'change' );
92+
settingParentId = data[ postSettingId ].post_parent;
93+
$( '#parent_id' ).val( settingParentId > 0 ? String( settingParentId ) : '' ).trigger( 'change' );
8294
$( '#new-post-slug' ).val( data[ postSettingId ].post_name );
8395
$( '#editable-post-name, #editable-post-name-full' ).text( data[ postSettingId ].post_name );
8496
}

js/edit-post-preview-customize.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ var EditPostPreviewCustomize = (function( $, api ) {
1414
}
1515

1616
component.init = function() {
17-
component.populateSettings();
18-
19-
wp.customize.bind( 'ready', function() {
17+
api.bind( 'ready', function() {
2018
component.ready();
2119
} );
2220
};
@@ -28,6 +26,14 @@ var EditPostPreviewCustomize = (function( $, api ) {
2826
*/
2927
component.populateSettings = function() {
3028
var itemId, settings;
29+
30+
// Only run once.
31+
if ( component.settingsPopulated ) {
32+
return;
33+
}
34+
component.settingsPopulated = true;
35+
api.previewer.unbind( 'customized-posts', component.populateSettings );
36+
3137
itemId = 'previewedCustomizePostSettings[' + String( component.data.previewed_post.ID ) + ']';
3238
settings = sessionStorage.getItem( itemId );
3339
if ( ! settings ) {
@@ -58,8 +64,11 @@ var EditPostPreviewCustomize = (function( $, api ) {
5864
*/
5965
component.ready = function() {
6066

67+
// Wait to populate the settings until the customized-posts message is received so we know the preview is ready to receive mesages.
68+
api.previewer.bind( 'customized-posts', component.populateSettings );
69+
6170
// Prevent 'saved' state from becoming false, since we only want to save from the admin page.
62-
wp.customize.state( 'saved' ).set( true ).validate = function() {
71+
api.state( 'saved' ).set( true ).validate = function() {
6372
return true;
6473
};
6574

@@ -74,15 +83,15 @@ var EditPostPreviewCustomize = (function( $, api ) {
7483
*
7584
* @see wp.customize.Loader
7685
*/
77-
component.parentFrame = new wp.customize.Messenger( {
78-
url: wp.customize.settings.url.parent,
86+
component.parentFrame = new api.Messenger( {
87+
url: api.settings.url.parent,
7988
channel: 'loader'
8089
} );
8190

8291
// @todo Include nonce?
8392
component.parentFrame.bind( 'populate-setting', function( setting ) {
84-
if ( wp.customize.has( setting.id ) ) {
85-
wp.customize( setting.id ).set( setting.value );
93+
if ( api.has( setting.id ) ) {
94+
api( setting.id ).set( setting.value );
8695
}
8796
} );
8897

php/class-wp-customize-dynamic-control.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ protected function content_template() {
9191
/>
9292
{{{ data.label }}}
9393
<# if ( data.description ) { #>
94-
<span class="description customize-control-description">{{ data.description }}</span>
94+
<span class="description customize-control-description">{{{ data.description }}}</span>
9595
<# } #>
9696
</label>
9797
<# } else { #>
9898
<span class="customize-control-title"><label for="{{ data.input_id }}">{{ data.label }}</label></span>
9999
<# if ( data.description ) { #>
100-
<span class="description customize-control-description">{{ data.description }}</span>
100+
<span class="description customize-control-description">{{{ data.description }}}</span>
101101
<# } #>
102102
<# if ( 'textarea' === data.field_type ) { #>
103103
<textarea

php/class-wp-customize-posts-preview.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,11 @@ public function filter_the_posts_to_preview_settings( array $posts, WP_Query $qu
275275
* @type string $sort_column Supported.
276276
* @type string $authors Supported.
277277
* @type string $post_status Supported.
278+
* @type int $number Supported, but there won't be 100% fidelity due to customized posts being amended to the subset results without being aware of underlying placement in full results.
278279
* @type array $exclude No special support needed.
279280
* @type array $include No special support needed.
280281
* @type string $meta_key Not supported.
281282
* @type string $meta_value Not supported.
282-
* @type int $number Not supported.
283283
* @type int $offset Not supported.
284284
* @type bool $hierarchical Not needing to be examined since this is a property of the registered post type itself.
285285
* @type string $post_type Not needing to be examined since post_type is immutable.
@@ -293,7 +293,7 @@ public function filter_get_pages_to_preview_settings( $initial_posts, $args ) {
293293
return $initial_posts;
294294
}
295295

296-
$unsupported_args = array( 'number', 'offset', 'meta_key', 'meta_value' );
296+
$unsupported_args = array( 'offset', 'meta_key', 'meta_value' );
297297
foreach ( $unsupported_args as $unsupported_arg ) {
298298
if ( ! empty( $args[ $unsupported_arg ] ) ) {
299299
_doing_it_wrong( 'get_pages', sprintf( esc_html__( 'The %s argument for get_pages() is not supported by Customize Posts.', 'customize-posts' ), esc_html( $unsupported_arg ) ), '0.8.0' );
@@ -330,6 +330,7 @@ public function filter_get_pages_to_preview_settings( $initial_posts, $args ) {
330330
$args['include'] = array_filter( wp_parse_id_list( $args['include'] ) );
331331
$args['parent'] = intval( $args['parent'] );
332332
$args['child_of'] = intval( $args['child_of'] );
333+
$args['number'] = intval( $args['number'] );
333334

334335
if ( ! empty( $args['include'] ) ) {
335336
$args['child_of'] = 0; // Ignore child_of, parent, exclude, meta_key, and meta_value params if using include.
@@ -493,6 +494,10 @@ public function filter_get_pages_to_preview_settings( $initial_posts, $args ) {
493494
usort( $filtered_posts, array( $this, 'compare_posts_for_get_pages' ) );
494495
$this->current_get_pages_args = array();
495496

497+
if ( ! empty( $args['number'] ) ) {
498+
$filtered_posts = array_slice( $filtered_posts, 0, $args['number'] );
499+
}
500+
496501
return array_values( $filtered_posts );
497502
}
498503

@@ -1063,6 +1068,9 @@ public function get_post_field_partial_schema( $field_id = '' ) {
10631068
'post_status' => array(
10641069
'fallback_refresh' => true,
10651070
),
1071+
'post_parent' => array(
1072+
'fallback_refresh' => true,
1073+
),
10661074
'post_date' => array(
10671075
'selector' => 'time.entry-date',
10681076
'fallback_refresh' => false,

php/class-wp-customize-posts.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ public function get_author_choices() {
462462
foreach ( (array) $users as $user ) {
463463
$choices[] = array(
464464
'value' => (int) $user->ID,
465-
'text' => esc_html( sprintf( _x( '%1$s (%2$s)', 'user dropdown', 'customize-posts' ), $user->display_name, $user->user_login ) ),
465+
'text' => sprintf( _x( '%1$s (%2$s)', 'user dropdown', 'customize-posts' ), $user->display_name, $user->user_login ),
466466
);
467467
}
468468
}
@@ -599,7 +599,7 @@ public function enqueue_scripts() {
599599
$exports = array(
600600
'postTypes' => $post_types,
601601
'postStatusChoices' => $this->get_post_status_choices(),
602-
'authorChoices' => $this->get_author_choices(),
602+
'authorChoices' => $this->get_author_choices(), // @todo Use Ajax to fetch this data or Customize Object Selector (once it supports users).
603603
'dateMonthChoices' => $this->get_date_month_choices(),
604604
'initialServerDate' => current_time( 'mysql', false ),
605605
'initialServerTimestamp' => floor( microtime( true ) * 1000 ),
@@ -614,11 +614,23 @@ public function enqueue_scripts() {
614614
'fieldExcerptLabel' => __( 'Excerpt', 'customize-posts' ),
615615
'fieldDiscussionLabel' => __( 'Discussion', 'customize-posts' ),
616616
'fieldAuthorLabel' => __( 'Author', 'customize-posts' ),
617+
'fieldParentLabel' => __( 'Parent', 'customize-posts' ),
617618
'noTitle' => __( '(no title)', 'customize-posts' ),
618619
'theirChange' => __( 'Their change: %s', 'customize-posts' ),
619620
'openEditor' => __( 'Open Editor', 'customize-posts' ), // @todo Move this into editor control?
620621
'closeEditor' => __( 'Close Editor', 'customize-posts' ),
621622
'invalidDateError' => __( 'Whoops, the provided date is invalid.', 'customize-posts' ),
623+
'installCustomizeObjectSelector' => sprintf(
624+
__( 'This control depends on having the %s plugin installed and activated.', 'customize-posts' ),
625+
sprintf(
626+
'<a href="%s" target="_blank">%s</a>',
627+
'https://github.com/xwp/wp-customize-object-selector',
628+
__( 'Customize Object Selector', 'customize-posts' )
629+
)
630+
),
631+
632+
/* translators: %s post type */
633+
'jumpToPostPlaceholder' => __( 'Jump to %s', 'customize-posts' ),
622634
),
623635
);
624636

tests/php/test-class-wp-customize-posts-preview.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,40 @@ public function test_filter_get_pages_to_preview_settings_parent_and_exclude_tre
449449
$this->assertEquals( array( $page_c, $page_e ), wp_list_pluck( get_pages( array( 'parent' => $page_b ) ), 'ID' ) );
450450
}
451451

452+
/**
453+
* Test get_pages() with number args.
454+
*
455+
* @see get_pages()
456+
* @covers WP_Customize_Posts_Preview::filter_get_pages_to_preview_settings()
457+
*/
458+
public function test_filter_get_pages_to_preview_settings_number() {
459+
$page_a = $this->factory()->post->create( array( 'post_title' => 'Page A', 'post_type' => 'page' ) );
460+
$page_a1 = $this->factory()->post->create( array( 'post_title' => 'Page A.1', 'post_type' => 'page', 'post_parent' => $page_a ) );
461+
$page_a2 = $this->factory()->post->create( array( 'post_title' => 'Page A.2', 'post_type' => 'page', 'post_parent' => $page_a ) );
462+
463+
$pages = get_pages( array( 'parent' => $page_a, 'number' => 1, 'sort_column' => 'post_title', 'sort_order' => 'ASC' ) );
464+
$this->assertEquals( array( $page_a1 ), wp_list_pluck( $pages, 'ID' ) );
465+
$pages = get_pages( array( 'parent' => $page_a, 'number' => 1, 'sort_column' => 'post_title', 'sort_order' => 'DESC' ) );
466+
$this->assertEquals( array( $page_a2 ), wp_list_pluck( $pages, 'ID' ) );
467+
468+
// Now try adding a new sibling.
469+
$this->posts_component->preview->customize_preview_init();
470+
$page_a3_post_obj = $this->posts_component->insert_auto_draft_post( 'page' );
471+
$page_a3 = $page_a3_post_obj->ID;
472+
$page_a3_setting_id = WP_Customize_Post_Setting::get_post_setting_id( get_post( $page_a3 ) );
473+
$page_a3_setting = $this->posts_component->manager->add_setting( new WP_Customize_Post_Setting( $this->posts_component->manager, $page_a3_setting_id ) );
474+
$this->posts_component->manager->set_post_value( $page_a3_setting_id, array_merge(
475+
$page_a3_setting->value(),
476+
array( 'post_parent' => $page_a, 'post_title' => 'Page A.3' )
477+
) );
478+
$page_a3_setting->preview();
479+
480+
$pages = get_pages( array( 'parent' => $page_a, 'number' => 1, 'sort_column' => 'post_title', 'sort_order' => 'ASC' ) );
481+
$this->assertEquals( array( $page_a1 ), wp_list_pluck( $pages, 'ID' ) );
482+
$pages = get_pages( array( 'parent' => $page_a, 'number' => 1, 'sort_column' => 'post_title', 'sort_order' => 'DESC' ) );
483+
$this->assertEquals( array( $page_a3 ), wp_list_pluck( $pages, 'ID' ) );
484+
}
485+
452486
/**
453487
* Test filter_the_posts_to_tally_orderby_keys().
454488
*

tests/php/test-class-wp-customize-posts.php

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -305,23 +305,6 @@ public function test_get_post_status_choices() {
305305
}
306306
}
307307

308-
/**
309-
* Tests get_author_choices().
310-
*
311-
* @covers WP_Customize_Posts::get_author_choices()
312-
*/
313-
public function test_get_author_choices() {
314-
$posts = new WP_Customize_Posts( $this->wp_customize );
315-
$choices = $posts->get_author_choices();
316-
$this->assertTrue( count( $choices ) > 0 );
317-
foreach ( $choices as $choice ) {
318-
$this->assertInternalType( 'array', $choice );
319-
$this->assertArrayHasKey( 'text', $choice );
320-
$this->assertArrayHasKey( 'value', $choice );
321-
$this->assertTrue( (bool) get_user_by( 'ID', $choice['value'] ) );
322-
}
323-
}
324-
325308
/**
326309
* Get month choices.
327310
*
@@ -385,7 +368,6 @@ public function test_enqueue_scripts() {
385368
$this->assertArrayHasKey( 'post', $exports['postTypes'] );
386369
$this->assertArrayHasKey( 'postStatusChoices', $exports );
387370
$this->assertArrayHasKey( 'dateMonthChoices', $exports );
388-
$this->assertArrayHasKey( 'authorChoices', $exports );
389371
$this->assertArrayHasKey( 'initialServerDate', $exports );
390372
$this->assertInternalType( 'int', strtotime( $exports['initialServerDate'] ) );
391373
$this->assertArrayHasKey( 'initialServerTimestamp', $exports );

0 commit comments

Comments
 (0)