Skip to content

Instantly share code, notes, and snippets.

@westonruter
Last active December 8, 2017 12:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save westonruter/00c351830e0a15cef7672b748720a7ff to your computer and use it in GitHub Desktop.
Save westonruter/00c351830e0a15cef7672b748720a7ff to your computer and use it in GitHub Desktop.
WPSE 286375: A dynamic dropdown-pages control. https://wordpress.stackexchange.com/q/286375/8521
<?xml version="1.0"?>
<ruleset name="WPSE 286375 Plugin">
<rule ref="WordPress-Core" />
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" value="wpse-286375,default" />
</properties>
</rule>
<rule ref="WordPress-Docs" />
<rule ref="WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned">
<severity>0</severity>
</rule>
<rule ref="Generic.Formatting.MultipleStatementAlignment.NotSameWarning">
<severity>0</severity>
</rule>
<rule ref="WordPress.Arrays.ArrayDeclarationSpacing.AssociativeKeyFound">
<severity>0</severity>
</rule>
<rule ref="WordPress.Files.FileName.InvalidClassFileName">
<exclude-pattern>wpse-286375.php</exclude-pattern>
</rule>
<arg name="extensions" value="php"/>
<arg value="s"/>
<file>.</file>
<exclude-pattern>*/node_modules/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/dev-lib/*</exclude-pattern>
</ruleset>
/* globals wp */
/* exported wpse286375controls */
var wpse286375controls = ( function( api ) {
'use strict';
var component = {
defaultParams: {
label: '',
description: ''
}
};
/**
* Init.
*
* @param {object} defaultParams - Default params for control, especially translated strings.
* @returns {void}
*/
component.init = function( defaultParams ) {
component.defaultParams = defaultParams || {};
api.bind( 'ready', component.addControl );
};
/**
* Set the active states for the device controls.
*
* @returns {void}
*/
component.addControl = function() {
api.control.add( new api.Control( 'special_page', _.extend(
{},
component.defaultParams,
{
type: 'dropdown-pages',
section: 'static_front_page',
}
) ) );
};
return component;
} )( wp.customize );
<?php
/**
* Plugin Name: WPSE 286375
* Description: A dynamic dropdown-pages control.
* Plugin URI: https://wordpress.stackexchange.com/q/286375
* Version: 0.1.0
* Author: Weston Ruter, XWP
* Author URI: https://weston.ruter.net/
* License: GPLv2+
*
* @package WPSE_286375
*/
/**
* Class WPSE_286375_Plugin
*/
class WPSE_286375_Plugin {
/**
* Init.
*/
public function init() {
add_action( 'customize_register', array( $this, 'customize_register' ) );
add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_control_templates' ) );
add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_controls_scripts' ) );
}
/**
* Customize register.
*
* @param WP_Customize_Manager $wp_customize Manager.
*/
public function customize_register( WP_Customize_Manager $wp_customize ) {
$wp_customize->add_setting( 'favorite_page', array(
'default' => 0,
'sanitize_callback' => function( $value ) {
$value = intval( $value );
if ( $value <= 0 ) {
return new WP_Error( 'invalid_page_id_int', __( 'Page ID must be integer.', 'wpse-286375' ) );
}
if ( 'page' !== get_post_type( $value ) ) {
return new WP_Error( 'invalid_page_id_post_type', __( 'ID must be for a page.', 'wpse-286375' ) );
}
return $value;
},
) );
}
/**
* Enqueue controls scripts.
*/
public function enqueue_controls_scripts() {
$handle = 'wpse-286375-controls';
wp_enqueue_script( $handle, plugin_dir_url( __FILE__ ) . 'wpse-286375-controls.js', array( 'customize-controls' ) );
$exports = array(
'label' => __( 'Featured Page', 'wpse-286375' ),
'description' => __( 'Select your a page that you\'d like to feature on the site.', 'wpse-286375' ),
'setting' => 'favorite_page',
);
wp_add_inline_script( $handle, sprintf( 'wpse286375controls.init( %s );', wp_json_encode( $exports ) ) );
}
/**
* Print templates.
*
* @global WP_Customize_Manager $wp_customize
*/
public function print_control_templates() {
global $wp_customize;
?>
<script type="text/html" id="tmpl-customize-control-dropdown-pages-content">
<#
var inputId = _.uniqueId( 'customize-control-dropdown-pages-input-' );
var descriptionId = _.uniqueId( 'customize-control-dropdown-pages-description-' );
var describedByAttr = data.description ? ' aria-describedby="' + descriptionId + '" ' : '';
#>
<# if ( data.label ) { #>
<label for="{{ inputId }}" class="customize-control-title">
{{ data.label }}
</label>
<# } #>
<# if ( data.description ) { #>
<span id="{{ descriptionId }}" class="description customize-control-description">{{{ data.description }}}</span>
<# } #>
<#
var inputAttrs = {
id: inputId,
'data-customize-setting-key-link': 'default'
};
if ( 'textarea' === data.type ) {
inputAttrs.rows = '5';
} else if ( 'button' === data.type ) {
inputAttrs['class'] = 'button button-secondary';
inputAttrs.type = 'button';
} else {
inputAttrs.type = data.type;
}
if ( data.description ) {
inputAttrs['aria-describedby'] = descriptionId;
}
_.extend( inputAttrs, data.input_attrs );
#>
<# delete inputAttrs.type; #>
<?php
$show_option_none = __( '&mdash; Select &mdash;', 'default' );
$option_none_value = '0';
$dropdown = wp_dropdown_pages(
array(
'name' => '{{ inputId }}',
'echo' => 0,
'show_option_none' => $show_option_none,
'option_none_value' => $option_none_value,
)
);
if ( empty( $dropdown ) ) {
$dropdown = sprintf( '<select id="%1$s" name="%1$s">', '{{ inputId }}' );
$dropdown .= sprintf( '<option value="%1$s">%2$s</option>', esc_attr( $option_none_value ), esc_html( $show_option_none ) );
$dropdown .= '</select>';
}
// Hackily add in the data link parameter.
$dropdown = str_replace(
'<select',
'<select <# _.each( _.extend( inputAttrs ), function( value, key ) { #> {{{ key }}}="{{ value }}" <# }); #> ',
$dropdown
);
// Even more hacikly add auto-draft page stubs.
// @todo Eventually this should be removed in favor of the pages being injected into the underlying get_pages() call. See <https://github.com/xwp/wp-customize-posts/pull/250>.
$nav_menus_created_posts_setting = $wp_customize->get_setting( 'nav_menus_created_posts' );
if ( $nav_menus_created_posts_setting && current_user_can( 'publish_pages' ) ) {
$auto_draft_page_options = '';
foreach ( $nav_menus_created_posts_setting->value() as $auto_draft_page_id ) {
$post = get_post( $auto_draft_page_id );
if ( $post && 'page' === $post->post_type ) {
$auto_draft_page_options .= sprintf( '<option value="%1$s">%2$s</option>', esc_attr( $post->ID ), esc_html( $post->post_title ) );
}
}
if ( $auto_draft_page_options ) {
$dropdown = str_replace( '</select>', $auto_draft_page_options . '</select>', $dropdown );
}
}
echo $dropdown;
?>
<?php if ( current_user_can( 'publish_pages' ) && current_user_can( 'edit_theme_options' ) ) : // Currently tied to menus functionality. ?>
<# if ( data.allowAddition ) { #>
<button type="button" class="button-link add-new-toggle">
<?php
/* translators: %s: add new page label */
printf( __( '+ %s', 'default' ), get_post_type_object( 'page' )->labels->add_new_item );
?>
</button>
<div class="new-content-item">
<label for="create-input-{{ inputId }}"><span class="screen-reader-text"><?php esc_html_e( 'New page title', 'default' ); ?></span></label>
<input type="text" id="create-input-{{ inputId }}" class="create-item-input" placeholder="<?php esc_attr_e( 'New page title&hellip;', 'default' ); ?>">
<button type="button" class="button add-content"><?php esc_html_e( 'Add', 'default' ); ?></button>
</div>
<# } #>
<?php endif; ?>
</script>
<?php
}
}
if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '4.9', '>=' ) ) {
$wpse_286375 = new WPSE_286375_Plugin();
$wpse_286375->init();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment