Skip to content

Instantly share code, notes, and snippets.

@westonruter
Last active September 27, 2016 06:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save westonruter/ed4ae3f8b6f6d653e0c6 to your computer and use it in GitHub Desktop.
Save westonruter/ed4ae3f8b6f6d653e0c6 to your computer and use it in GitHub Desktop.
<?php
/**
* WP_Customize_Rich_Text_Control class
*
* @package WelcomeMessage
*/
namespace WelcomeMessage;
/**
* Customize Rich Text Control class.
*
* @see \WP_Customize_Control
*/
class WP_Customize_Rich_Text_Control extends \WP_Customize_Control {
/**
* Control type.
*
* @since 4.2.0
* @access public
* @var string
*/
public $type = 'rich_text';
/**
* Editor arguments.
*
* @see \_WP_Editors::parse_settings()
* @var array
*/
public $editor_arguments = array();
/**
* Constructor.
*
* @since 4.1.0
* @since 4.2.0 Moved from WP_Customize_Upload_Control.
*
* @param \WP_Customize_Manager $manager Customizer bootstrap instance.
* @param string $id Control ID.
* @param array $args Optional. Arguments to override class property defaults.
*/
public function __construct( $manager, $id, $args = array() ) {
if ( ! isset( $args['editor_arguments'] ) ) {
$args['editor_arguments'] = array();
}
$args['editor_arguments'] = wp_parse_args( $args['editor_arguments'], array(
'teeny' => true,
) );
parent::__construct( $manager, $id, $args );
}
/**
* Enqueue control related scripts/styles.
*/
public function enqueue() {
$handle = 'customize-rich-text-control';
$src = plugin_dir_url( __FILE__ ) . '/customize-rich-text-control.js';
$deps = array( 'customize-controls', 'editor' );
$ver = false;
$in_footer = true;
wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );
add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_editor' ), 0 );
// @todo These should be included in \_WP_Editors::editor_settings()
if ( false === has_action( 'customize_controls_print_footer_scripts', array( '_WP_Editors', 'enqueue_scripts' ) ) ) {
add_action( 'customize_controls_print_footer_scripts', array( '_WP_Editors', 'enqueue_scripts' ) );
}
}
/**
* Render rich text editor.
*/
public function render_editor() {
echo '<div hidden>';
wp_editor( '', "$this->id-customize-rich-text-control", $this->editor_arguments );
echo '</div>';
}
/**
* Refresh the parameters passed to the JavaScript via JSON.
*
* @since 3.4.0
* @since 4.2.0 Moved from WP_Customize_Upload_Control.
*
* @see WP_Customize_Control::to_json()
* @return array Exported data.
*/
public function json() {
$exported = parent::json();
$exported['editor_arguments'] = $this->editor_arguments;
return $exported;
}
/**
* Override render_content to be no-op since content is exported via to_json for deferred embedding.
*/
public function render_content() {}
/**
* An Underscore (JS) template for this control's content (but not its container).
*
* Class variables for this control class are available in the `data` JS object;
* export custom variables by overriding {@see WP_Customize_Control::to_json()}.
*
* @see WP_Customize_Control::print_template()
*/
protected function content_template() {
?>
<label for="{{ data.settings['default'] }}-button">
<# if ( data.label ) { #>
<span class="customize-control-title">{{ data.label }}</span>
<# } #>
<# if ( data.description ) { #>
<span class="description customize-control-description">{{{ data.description }}}</span>
<# } #>
</label>
<div class="wp-editor-placeholder"></div>
<?php
}
}
/* global wp, jQuery, tinyMCE */
(function( api, $ ) {
// @todo Is there a better way to listen for when TinyMCE has finished initializing the editors?
var windowLoaded = $.Deferred();
$( window ).on( 'load', function() {
tinyMCE.on( '' );
windowLoaded.resolve();
} );
/**
* @class
*
* @todo Populate with initial content
* @todo Update setting when rich text editor changes.
*/
api.controlConstructor.rich_text = api.Control.extend({
/**
* Render the content and inject the TinyMCE editor into the control.
*/
renderContent: function() {
var control = this;
api.Control.prototype.renderContent.call( control );
control.container.find( '.wp-editor-placeholder' ).replaceWith( $( '#wp-' + control.id + '-customize-rich-text-control-wrap' ) );
},
/**
* Embed the control into the page.
*/
embed: function() {
var control = this,
inject;
// Watch for changes to the section state
inject = function( sectionId ) {
var parentContainer;
if ( ! sectionId ) { // @todo allow a control to be embedded without a section, for instance a control embedded in the frontend
return;
}
// Wait for the section to be registered
api.section( sectionId, function( section ) {
var deferredDependencies = [ windowLoaded, section.deferred.embedded ];
// Wait for the window to load (and thus the Tiny MCE editor) and the section to be ready/initialized
$.when( deferredDependencies ).then( function() {
parentContainer = section.container.find( 'ul:first' );
if ( ! control.container.parent().is( parentContainer ) ) {
parentContainer.append( control.container );
control.renderContent();
}
// @todo tinyMCE.onAddEditor?
setTimeout( function() {
control.deferred.embedded.resolve();
}, 1000 );
});
});
};
control.section.bind( inject );
inject( control.section.get() );
},
/**
* Ready.
*/
ready: function() {
var control = this, editor = control.getEditor(), element, suspendRecursion;
element = new api.Element( $( '#' + control.id + '-customize-rich-text-control' ) );
control.elements.push( element );
element.set( control.setting() );
element.sync( control.setting );
control.setting.bind( function( value ) {
if ( ! suspendRecursion ) {
editor.setContent( value );
}
} );
if ( editor ) {
editor.setContent( control.setting() );
editor.on( 'input change keyup', function() {
var value = wp.editor.removep( editor.getContent() );
suspendRecursion = true;
control.setting.set( value );
suspendRecursion = false;
} );
} else {
// @todo Initialize when the editor gets added.
}
},
/**
* Get the tinyMCE editor for this control.
*
* @returns {tinyMCE.Editor|null}
*/
getEditor: function() {
var control = this;
return tinyMCE.get( control.id + '-customize-rich-text-control' );
},
/**
* Focus on editor content.
*
* @param {Object} [params]
* @param {Function} [params.completeCallback]
*/
focus: function( params ) {
var control, completeCallback, focus;
control = this;
params = params || {};
focus = function() {
var editor = control.getEditor();
if ( editor ) {
control.container[0].scrollIntoView();
editor.focus();
} else {
// Fallback in case the editor hasn't been initialized yet.
control.container.find( 'input, select, textarea, button, object, a[href], [tabindex]' ).filter( ':visible' ).first().focus();
}
};
if ( params.completeCallback ) {
completeCallback = params.completeCallback;
params.completeCallback = function() {
focus();
completeCallback();
};
} else {
params.completeCallback = focus;
}
if ( control.expand ) {
control.expand( params );
} else {
params.completeCallback();
}
}
});
}( wp.customize, jQuery ) );
/* global wp */
(function( api ) {
api.bind( 'preview-ready', function() {
// @todo We can initialize a TinyMCE editor in the preview.
} );
}( wp.customize ) );
<?php
/**
* Plugin name: Welcome Message
* Description: Demonstration of selective refresh in the Customizer.
* Author: Weston Ruter, XWP
* Plugin URL:
*
* @todo Let this be FooterText instead
*
* @package WelcomeMessage
*/
namespace WelcomeMessage;
/**
* Render the welcome message.
*
* This function can be used in the template directly.
* This function is called after the associated Customizer setting has already
* been previewed, so we can call it just as if we were in the template normally.
*
* @see \get_template_part()
*/
function the_welcome_message() {
// @todo What about the before/after container?
echo apply_filters( 'the_content', get_option( 'welcome_message' ) );
}
/**
* Add welcome message container to document before sidebar.
*/
function add_welcome_message_container() {
echo '<div class="welcome-message">';
the_welcome_message();
echo '</div>';
}
add_action( 'get_sidebar', __NAMESPACE__ . '\add_welcome_message_container' );
/**
* Enqueue preview scripts.
*/
function enqueue_preview_scripts() {
$handle = 'welcome-message-preview';
$src = plugin_dir_url( __FILE__ ) . '/welcome-message-preview.js';
$deps = array( 'customize-preview' );
$ver = false;
$in_footer = true;
wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );
}
add_action( 'customize_preview_init', function() {
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\enqueue_preview_scripts' );
} );
/**
* Register selective refresh partial.
*
* @param \WP_Customize_Manager $wp_customize Manager.
*/
function register_selective_refresh_partial( \WP_Customize_Manager $wp_customize ) {
require_once __DIR__ . '/class-wp-customize-rich-text-control.php';
$wp_customize->register_control_type( __NAMESPACE__ . '\WP_Customize_Rich_Text_Control' );
$customize_id = 'welcome_message';
$wp_customize->add_setting( $customize_id, array(
'type' => 'option',
'transport' => 'postMessage',
) );
$wp_customize->add_control( new WP_Customize_Rich_Text_Control( $wp_customize, $customize_id, array(
'label' => __( 'Welcome Message' ),
'settings' => $customize_id,
'section' => 'title_tagline',
) ) );
if ( isset( $wp_customize->selective_refresh ) ) {
$wp_customize->selective_refresh->add_partial( 'welcome_message', array(
'selector' => '.welcome-message',
'settings' => array( $customize_id ),
'render_callback' => __NAMESPACE__ . '\the_welcome_message',
) );
}
}
add_action( 'customize_register', __NAMESPACE__ . '\register_selective_refresh_partial', 100 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment