472 lines
9.6 KiB
PHP
472 lines
9.6 KiB
PHP
|
<?php
|
||
|
|
||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||
|
exit; // Exit if accessed directly
|
||
|
}
|
||
|
|
||
|
if ( ! class_exists( 'acf_form_customizer' ) ) :
|
||
|
|
||
|
#[AllowDynamicProperties]
|
||
|
class acf_form_customizer {
|
||
|
|
||
|
|
||
|
/*
|
||
|
* __construct
|
||
|
*
|
||
|
* This function will setup the class functionality
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 5/03/2014
|
||
|
* @since 5.0.0
|
||
|
*
|
||
|
* @param n/a
|
||
|
* @return n/a
|
||
|
*/
|
||
|
|
||
|
function __construct() {
|
||
|
|
||
|
// vars
|
||
|
$this->preview_values = array();
|
||
|
$this->preview_fields = array();
|
||
|
$this->preview_errors = array();
|
||
|
|
||
|
// actions
|
||
|
add_action( 'customize_controls_init', array( $this, 'customize_controls_init' ) );
|
||
|
add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ), 1, 1 );
|
||
|
add_action( 'customize_save', array( $this, 'customize_save' ), 1, 1 );
|
||
|
|
||
|
// save
|
||
|
add_filter( 'widget_update_callback', array( $this, 'save_widget' ), 10, 4 );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* admin_enqueue_scripts
|
||
|
*
|
||
|
* This action is run after post query but before any admin script / head actions.
|
||
|
* It is a good place to register all actions.
|
||
|
*
|
||
|
* @type action (admin_enqueue_scripts)
|
||
|
* @date 26/01/13
|
||
|
* @since 3.6.0
|
||
|
*
|
||
|
* @param N/A
|
||
|
* @return N/A
|
||
|
*/
|
||
|
|
||
|
function customize_controls_init() {
|
||
|
|
||
|
// load acf scripts
|
||
|
acf_enqueue_scripts(
|
||
|
array(
|
||
|
'context' => 'customize_controls',
|
||
|
)
|
||
|
);
|
||
|
|
||
|
// actions
|
||
|
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ), 1 );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* save_widget
|
||
|
*
|
||
|
* This function will hook into the widget update filter and save ACF data
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 27/05/2015
|
||
|
* @since 5.2.3
|
||
|
*
|
||
|
* @param $instance (array) widget settings
|
||
|
* @param $new_instance (array) widget settings
|
||
|
* @param $old_instance (array) widget settings
|
||
|
* @param $widget (object) widget info
|
||
|
* @return $instance
|
||
|
*/
|
||
|
|
||
|
function save_widget( $instance, $new_instance, $old_instance, $widget ) {
|
||
|
|
||
|
// bail early if not valid (customize + acf values + nonce)
|
||
|
if ( ! isset( $_POST['wp_customize'] ) || ! isset( $new_instance['acf'] ) || ! acf_verify_nonce( 'widget' ) ) {
|
||
|
return $instance;
|
||
|
}
|
||
|
|
||
|
// vars
|
||
|
$data = array(
|
||
|
'post_id' => "widget_{$widget->id}",
|
||
|
'values' => array(),
|
||
|
'fields' => array(),
|
||
|
);
|
||
|
|
||
|
// append values
|
||
|
$data['values'] = $new_instance['acf'];
|
||
|
|
||
|
// append fields (name => key relationship) - used later in 'acf/get_field_reference' for customizer previews
|
||
|
foreach ( $data['values'] as $k => $v ) {
|
||
|
|
||
|
// get field
|
||
|
$field = acf_get_field( $k );
|
||
|
|
||
|
// continue if no field
|
||
|
if ( ! $field ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// update
|
||
|
$data['fields'][ $field['name'] ] = $field['key'];
|
||
|
|
||
|
}
|
||
|
|
||
|
// append data to instance
|
||
|
$instance['acf'] = $data;
|
||
|
|
||
|
// return
|
||
|
return $instance;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* settings
|
||
|
*
|
||
|
* This function will return an array of cutomizer settings that include ACF data
|
||
|
* similar to `$customizer->settings();`
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 22/03/2016
|
||
|
* @since 5.3.2
|
||
|
*
|
||
|
* @param $customizer (object)
|
||
|
* @return $value (mixed)
|
||
|
*/
|
||
|
|
||
|
function settings( $customizer ) {
|
||
|
|
||
|
// vars
|
||
|
$data = array();
|
||
|
$settings = $customizer->settings();
|
||
|
|
||
|
// bail early if no settings
|
||
|
if ( empty( $settings ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// loop over settings
|
||
|
foreach ( $settings as $setting ) {
|
||
|
|
||
|
// vars
|
||
|
$id = $setting->id;
|
||
|
|
||
|
// verify settings type
|
||
|
if ( substr( $id, 0, 6 ) == 'widget' || substr( $id, 0, 7 ) == 'nav_menu' ) {
|
||
|
// allow
|
||
|
} else {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// get value
|
||
|
$value = $setting->post_value();
|
||
|
|
||
|
// bail early if no acf
|
||
|
if ( ! is_array( $value ) || ! isset( $value['acf'] ) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// set data
|
||
|
$setting->acf = $value['acf'];
|
||
|
|
||
|
// append
|
||
|
$data[] = $setting;
|
||
|
|
||
|
}
|
||
|
|
||
|
// bail early if no settings
|
||
|
if ( empty( $data ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// return
|
||
|
return $data;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* customize_preview_init
|
||
|
*
|
||
|
* This function is called when customizer preview is initialized
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 22/03/2016
|
||
|
* @since 5.3.2
|
||
|
*
|
||
|
* @param $customizer (object)
|
||
|
* @return n/a
|
||
|
*/
|
||
|
|
||
|
function customize_preview_init( $customizer ) {
|
||
|
|
||
|
// get customizer settings (widgets)
|
||
|
$settings = $this->settings( $customizer );
|
||
|
|
||
|
// bail early if no settings
|
||
|
if ( empty( $settings ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// append values
|
||
|
foreach ( $settings as $setting ) {
|
||
|
|
||
|
// get acf data
|
||
|
$data = $setting->acf;
|
||
|
|
||
|
// append acf_value to preview_values
|
||
|
$this->preview_values[ $data['post_id'] ] = $data['values'];
|
||
|
$this->preview_fields[ $data['post_id'] ] = $data['fields'];
|
||
|
|
||
|
}
|
||
|
|
||
|
// bail early if no preview_values
|
||
|
if ( empty( $this->preview_values ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// add filters
|
||
|
add_filter( 'acf/pre_load_value', array( $this, 'pre_load_value' ), 10, 3 );
|
||
|
add_filter( 'acf/pre_load_reference', array( $this, 'pre_load_reference' ), 10, 3 );
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pre_load_value
|
||
|
*
|
||
|
* Used to inject preview value
|
||
|
*
|
||
|
* @date 2/2/18
|
||
|
* @since 5.6.5
|
||
|
*
|
||
|
* @param type $var Description. Default.
|
||
|
* @return type Description.
|
||
|
*/
|
||
|
|
||
|
function pre_load_value( $value, $post_id, $field ) {
|
||
|
|
||
|
// check
|
||
|
if ( isset( $this->preview_values[ $post_id ][ $field['key'] ] ) ) {
|
||
|
return $this->preview_values[ $post_id ][ $field['key'] ];
|
||
|
}
|
||
|
|
||
|
// return
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pre_load_reference
|
||
|
*
|
||
|
* Used to inject preview value
|
||
|
*
|
||
|
* @date 2/2/18
|
||
|
* @since 5.6.5
|
||
|
*
|
||
|
* @param type $var Description. Default.
|
||
|
* @return type Description.
|
||
|
*/
|
||
|
|
||
|
function pre_load_reference( $field_key, $field_name, $post_id ) {
|
||
|
|
||
|
// check
|
||
|
if ( isset( $this->preview_fields[ $post_id ][ $field_name ] ) ) {
|
||
|
return $this->preview_fields[ $post_id ][ $field_name ];
|
||
|
}
|
||
|
|
||
|
// return
|
||
|
return $field_key;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* customize_save
|
||
|
*
|
||
|
* This function is called when customizer saves a widget.
|
||
|
* Normally, the widget_update_callback filter would be used, but the customizer disables this and runs a custom action
|
||
|
* class-customizer-settings.php will save the widget data via the function set_root_value which uses update_option
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 22/03/2016
|
||
|
* @since 5.3.2
|
||
|
*
|
||
|
* @param $customizer (object)
|
||
|
* @return n/a
|
||
|
*/
|
||
|
|
||
|
function customize_save( $customizer ) {
|
||
|
|
||
|
// get customizer settings (widgets)
|
||
|
$settings = $this->settings( $customizer );
|
||
|
|
||
|
// bail early if no settings
|
||
|
if ( empty( $settings ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// append values
|
||
|
foreach ( $settings as $setting ) {
|
||
|
|
||
|
// get acf data
|
||
|
$data = $setting->acf;
|
||
|
|
||
|
// save acf data
|
||
|
acf_save_post( $data['post_id'], $data['values'] );
|
||
|
|
||
|
// remove [acf] data from saved widget array
|
||
|
$id_data = $setting->id_data();
|
||
|
add_filter( 'pre_update_option_' . $id_data['base'], array( $this, 'pre_update_option' ), 10, 3 );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* pre_update_option
|
||
|
*
|
||
|
* this function will remove the [acf] data from widget insance
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 22/03/2016
|
||
|
* @since 5.3.2
|
||
|
*
|
||
|
* @param $post_id (int)
|
||
|
* @return $post_id (int)
|
||
|
*/
|
||
|
|
||
|
function pre_update_option( $value, $option, $old_value ) {
|
||
|
|
||
|
// bail early if no value
|
||
|
if ( empty( $value ) ) {
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
// loop over widgets
|
||
|
// WP saves all widgets (of the same type) as an array of widgets
|
||
|
foreach ( $value as $i => $widget ) {
|
||
|
|
||
|
// bail early if no acf
|
||
|
if ( ! isset( $widget['acf'] ) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// remove widget
|
||
|
unset( $value[ $i ]['acf'] );
|
||
|
|
||
|
}
|
||
|
|
||
|
// return
|
||
|
return $value;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* admin_footer
|
||
|
*
|
||
|
* This function will add some custom HTML to the footer of the edit page
|
||
|
*
|
||
|
* @type function
|
||
|
* @date 11/06/2014
|
||
|
* @since 5.0.0
|
||
|
*
|
||
|
* @param n/a
|
||
|
* @return n/a
|
||
|
*/
|
||
|
|
||
|
function admin_footer() {
|
||
|
|
||
|
?>
|
||
|
<script type="text/javascript">
|
||
|
(function($) {
|
||
|
|
||
|
// customizer saves widget on any input change, so unload is not needed
|
||
|
acf.unload.active = 0;
|
||
|
|
||
|
|
||
|
// hack customizer function to remove bug caused by WYSIWYG field using aunique ID
|
||
|
// customizer compares returned AJAX HTML with the HTML of the widget form.
|
||
|
// the _getInputsSignature() function is used to generate a string based of input name + id.
|
||
|
// because ACF generates a unique ID on the WYSIWYG field, this string will not match causing the preview function to bail.
|
||
|
// an attempt was made to remove the WYSIWYG unique ID, but this caused multiple issues in the wp-admin and altimately doesn't make sense with the tinymce rule that all editors must have a unique ID.
|
||
|
// source: wp-admin/js/customize-widgets.js
|
||
|
|
||
|
// vars
|
||
|
var WidgetControl = wp.customize.Widgets.WidgetControl.prototype;
|
||
|
|
||
|
|
||
|
// backup functions
|
||
|
WidgetControl.__getInputsSignature = WidgetControl._getInputsSignature;
|
||
|
WidgetControl.__setInputState = WidgetControl._setInputState;
|
||
|
|
||
|
|
||
|
// modify __getInputsSignature
|
||
|
WidgetControl._getInputsSignature = function( inputs ) {
|
||
|
|
||
|
// vars
|
||
|
var signature = this.__getInputsSignature( inputs );
|
||
|
safe = [];
|
||
|
|
||
|
|
||
|
// split
|
||
|
signature = signature.split(';');
|
||
|
|
||
|
|
||
|
// loop
|
||
|
for( var i in signature ) {
|
||
|
|
||
|
// vars
|
||
|
var bit = signature[i];
|
||
|
|
||
|
|
||
|
// bail early if acf is found
|
||
|
if( bit.indexOf('acf') !== -1 ) continue;
|
||
|
|
||
|
|
||
|
// append
|
||
|
safe.push( bit );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// update
|
||
|
signature = safe.join(';');
|
||
|
|
||
|
|
||
|
// return
|
||
|
return signature;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
// modify _setInputState
|
||
|
// this function deosn't seem to run on widget title/content, only custom fields
|
||
|
// either way, this function is not needed and will break ACF fields
|
||
|
WidgetControl._setInputState = function( input, state ) {
|
||
|
|
||
|
return true;
|
||
|
|
||
|
};
|
||
|
|
||
|
})(jQuery);
|
||
|
</script>
|
||
|
<?php
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
new acf_form_customizer();
|
||
|
|
||
|
endif;
|
||
|
|
||
|
?>
|