Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Last active February 17, 2016 07:13
Show Gist options
  • Save jonathantneal/ce0ebf8b19fd4e140a93 to your computer and use it in GitHub Desktop.
Save jonathantneal/ce0ebf8b19fd4e140a93 to your computer and use it in GitHub Desktop.
Updating Customizer from the preview itself
[data-customize-text]:hover, [data-customize-text]:focus {
border-radius: 2px;
outline: none;
}
[data-customize-text]:hover {
background-color: rgba(0,155,255,.125);
box-shadow: inset 0 0 5px 0 rgba(0,155,255,.25), 0 0 5px 0 rgba(0,155,255,.25);
cursor: pointer;
}
[data-customize-text]:focus {
box-shadow: inset 0 0 5px 0 rgba(0,155,255,.75), 0 0 5px 0 rgba(0,155,255,.75);
}
// when the initial HTML document has been completely loaded and parsed
document.addEventListener('DOMContentLoaded', function () {
// for each customizable text element
[].forEach.call(document.querySelectorAll('[data-customize-text]'), function (text) {
// find the corresponding control
var control = top.document.querySelector('[data-customize-setting-link="' + text.dataset.customizeText + '"]');
// if the control exists
if (control) {
// make the text element editable
text.contentEditable = true;
// when the text value changes
text.addEventListener('input', function () {
// sanitize the text
sanitizeContentEditableText(text);
// get the text value
var newValue = text.lastChild ? text.lastChild.nodeValue : '';
// if the control value is not the same as the text value
if (newValue !== control.value) {
// update the control value
control.value = newValue;
// dispatch a change event
control.dispatchEvent(new CustomEvent('change'));
}
});
// when the control value changes
control.addEventListener('input', function () {
// sanitize the text
sanitizeContentEditableText(text);
// get the text value
var oldValue = text.lastChild ? text.lastChild.nodeValue : '';
// if the control value is not the same as the text value
if (oldValue !== control.value) {
// update the text value
(text.lastChild || text.appendChild(document.createTextNode(''))).nodeValue = control.value;
}
});
}
});
});
function sanitizeContentEditableText(text) {
// get the first child of text
var childNode = text.firstChild;
// while a child exists
while (childNode) {
// prepare the next child
var nextNode = childNode.nextSibling;
// if the child is not text
if (childNode.nodeType !== 3) {
// go through every child of that child
while (childNode.lastChild) {
// and push it up to text
text.insertBefore(childNode.firstChild, nextNode);
}
// redefine the next child
nextNode = childNode.nextSibling;
// remove the child that is not text
text.removeChild(childNode);
}
// update the child to be the next child
childNode = nextNode;
}
// defragment remaining child text
text.normalize();
}
<?php
/* Customize Register
*
* This action hook is used to customize and manipulate the
* Theme Customization admin screen.
*/
function mytheme_customizer_register( $wp_customize ) {
$wp_customize->add_section( 'layout_section', array(
'title' => __( 'Layout', 'mytheme' ),
'priority' => 10
) );
$wp_customize->add_setting( 'subheading_text', array(
'default' => 'Site subheading',
'type' => 'theme_mod',
'transport' => 'postMessage'
) );
$wp_customize->add_control( 'subheading_text', array(
'label' => 'Subheading',
'section' => 'title_tagline',
'priority' => 10,
'type' => 'text'
) );
$wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
}
add_action( 'customize_register', 'mytheme_customizer_register' );
/* Customize Preview Init
*
* This action hook is used to enqueue assets directly in
* the Theme Customizer only.
*/
function mytheme_customize_preview_init() {
wp_enqueue_script( 'mytheme-customizer-js', get_template_directory_uri() . '/customizer.js' );
wp_enqueue_style( 'mytheme-customizer-css', get_template_directory_uri() . '/customizer.css' );
}
add_action( 'customize_preview_init', 'mytheme_customize_preview_init' );
/* Customize Preview Init
*
* This action hook is used to enqueue scripts and styles
* that are meant to appear on the front end.
*/
function mytheme_wp_enqueue_scripts() {
wp_enqueue_style( 'mytheme-style', get_stylesheet_uri() );
}
add_action( 'wp_enqueue_scripts', 'mytheme_wp_enqueue_scripts' );
/* Customizer Text Open / Close
*
* These methods are used to wrap editable text blocks
* on the front end when in the Theme Customizer only.
*/
function mytheme_customizer_text_open( $link ) {
if ( is_customize_preview() ) {
echo '<span data-customize-text="' . $link . '">';
}
}
function mytheme_customizer_text_close() {
if ( is_customize_preview() ) {
echo '</span>';
}
}
<?php wp_head(); ?>
<h1 class="heading"><?php
mytheme_customizer_text_open( 'blogname', 'text' );
echo esc_html( get_bloginfo('name') );
mytheme_customizer_text_close();
?></h1>
<h2 class="subheading"><?php
mytheme_customizer_text_open( 'subheading_text', 'text' );
echo esc_html( get_theme_mod( 'subheading_text' ) );
mytheme_customizer_text_close();
?></h2>
<?php wp_footer(); ?>
/*
Theme Name: Test
*/
body {
font: 100%/1.5 sans-serif;
margin: 1rem;
}
:first-child {
margin-top: 0;
}
:last-child {
margin-bottom: 0;
}
.heading {
box-shadow: 0 1px 0 0 #dddddd;
font-size: 2em;
line-height: 1;
margin-bottom: 1rem;
padding-bottom: .25rem;
}
.heading + .subheading {
font-size: 1em;
margin-top: -.5rem;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment