ot_options_id(), 'pages' => array( array( 'id' => 'ot_theme_options', 'parent_slug' => apply_filters( 'ot_theme_options_parent_slug', 'themes.php' ), 'page_title' => apply_filters( 'ot_theme_options_page_title', esc_html__( 'Theme Options', 'option-tree' ) ), 'menu_title' => apply_filters( 'ot_theme_options_menu_title', esc_html__( 'Theme Options', 'option-tree' ) ), 'capability' => $caps, 'menu_slug' => apply_filters( 'ot_theme_options_menu_slug', 'ot-theme-options' ), 'icon_url' => apply_filters( 'ot_theme_options_icon_url', null ), 'position' => apply_filters( 'ot_theme_options_position', null ), 'updated_message' => apply_filters( 'ot_theme_options_updated_message', esc_html__( 'Theme Options updated.', 'option-tree' ) ), 'reset_message' => apply_filters( 'ot_theme_options_reset_message', esc_html__( 'Theme Options reset.', 'option-tree' ) ), 'button_text' => apply_filters( 'ot_theme_options_button_text', esc_html__( 'Save Changes', 'option-tree' ) ), 'contextual_help' => apply_filters( 'ot_theme_options_contextual_help', $contextual_help ), 'sections' => apply_filters( 'ot_theme_options_sections', $sections ), 'settings' => apply_filters( 'ot_theme_options_settings', $settings ), ), ), ), ) ); // Filters the options.php to add the minimum user capabilities. add_filter( 'option_page_capability_' . ot_options_id(), function() use ( $caps ) { return $caps; }, 999 ); } } } if ( ! function_exists( 'ot_register_settings_page' ) ) { /** * Registers the Settings page. * * @access public * @since 2.1 */ function ot_register_settings_page() { global $ot_has_custom_theme_options; $custom_options = ( true === $ot_has_custom_theme_options || has_action( 'admin_init', 'custom_theme_options' ) || has_action( 'init', 'custom_theme_options' ) ); // Display UI Builder admin notice. if ( true === OT_SHOW_OPTIONS_UI && isset( $_REQUEST['page'] ) && 'ot-settings' === $_REQUEST['page'] && $custom_options ) { // phpcs:ignore /** * Error message for custom theme options. */ function ot_has_custom_theme_options() { echo '
' . esc_html__( 'The Theme Options UI Builder is being overridden by a custom file in your theme. Any changes you make via the UI Builder will not be saved.', 'option-tree' ) . '
width
', '' . $field_id . '
' ), 'error' );
} else {
$input_safe[ $key ] = absint( $value );
}
} elseif ( 'color' === $key ) {
$input_safe[ $key ] = ot_validate_setting( $value, 'colorpicker', $field_id );
} else {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
} elseif ( 'box-shadow' === $type ) {
$input_safe = array();
// Loop over array and check for values.
foreach ( (array) $input as $key => $value ) {
if ( 'inset' === $key ) {
$input_safe[ $key ] = 'inset';
} elseif ( 'color' === $key ) {
$input_safe[ $key ] = ot_validate_setting( $value, 'colorpicker', $field_id );
} else {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
} elseif ( 'checkbox' === $type ) {
$input_safe = array();
// Loop over array and check for values.
foreach ( (array) $input as $key => $value ) {
if ( ! empty( $value ) ) {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
} elseif ( 'colorpicker' === $type ) {
$input_safe = '';
// Only strings are allowed.
if ( is_string( $input ) ) {
/* translators: %s: the field id */
$string_color = esc_html__( 'The %s Colorpicker only allows valid hexadecimal or rgba values depending on the setting type.', 'option-tree' );
if ( 0 === preg_match( '/^#([a-f0-9]{6}|[a-f0-9]{3})$/i', $input ) && 0 === preg_match( '/^rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9\.]{1,4})\s*\)/i', $input ) ) {
add_settings_error( 'option-tree', 'invalid_hex_or_rgba', sprintf( $string_color, '' . $field_id . '
' ), 'error' );
} else {
$input_safe = $input;
}
}
} elseif ( 'colorpicker-opacity' === $type ) {
$input_safe = ot_validate_setting( $input, 'colorpicker', $field_id );
} elseif ( in_array( $type, array( 'category-checkbox', 'custom-post-type-checkbox', 'page-checkbox', 'post-checkbox', 'tag-checkbox', 'taxonomy-checkbox' ), true ) ) {
$input_safe = array();
// Loop over array and check for values.
foreach ( (array) $input as $key => $value ) {
if ( filter_var( $value, FILTER_VALIDATE_INT ) && 0 < $value ) {
$input_safe[ $key ] = absint( $value );
}
}
} elseif ( in_array( $type, array( 'category-select', 'custom-post-type-select', 'page-select', 'post-select', 'tag-select', 'taxonomy-select' ), true ) ) {
$input_safe = '';
if ( filter_var( $input, FILTER_VALIDATE_INT ) && 0 < $input ) {
$input_safe = absint( $input );
}
} elseif ( in_array( $type, array( 'css', 'javascript', 'text', 'textarea', 'textarea-simple' ), true ) ) {
if ( ! function_exists( '_filter_wp_kses_post' ) ) {
/**
* Filter the allowed HTML and safe CSS styles.
*
* @since 2.7.2
*
* @param bool $add Whether to add or remove the filter.
*/
function _filter_wp_kses_post( $add = true ) {
$css_filter = function ( $attr ) {
array_push( $attr, 'display', 'visibility' );
$attr = apply_filters( 'ot_safe_style_css', $attr );
return $attr;
};
$html_filter = function ( $tags, $context ) {
if ( 'post' === $context ) {
if ( current_user_can( 'unfiltered_html' ) || true === OT_ALLOW_UNFILTERED_HTML ) {
$tags['script'] = array_fill_keys( array( 'async', 'charset', 'defer', 'src', 'type' ), true );
$tags['style'] = array_fill_keys( array( 'media', 'type' ), true );
$tags['iframe'] = array_fill_keys( array( 'align', 'allowfullscreen', 'class', 'frameborder', 'height', 'id', 'longdesc', 'marginheight', 'marginwidth', 'name', 'sandbox', 'scrolling', 'src', 'srcdoc', 'style', 'width' ), true );
$tags['noscript'] = true;
$tags = apply_filters( 'ot_allowed_html', $tags );
}
}
return $tags;
};
if ( $add ) {
add_filter( 'safe_style_css', $css_filter );
add_filter( 'wp_kses_allowed_html', $html_filter, 10, 2 );
} else {
remove_filter( 'safe_style_css', $css_filter );
remove_filter( 'wp_kses_allowed_html', $html_filter );
}
}
}
_filter_wp_kses_post( true );
$input_safe = wp_kses_post( $input );
_filter_wp_kses_post( false );
} elseif ( 'date-picker' === $type || 'date-time-picker' === $type ) {
if ( ! empty( $input ) && (bool) strtotime( $input ) ) {
$input_safe = sanitize_text_field( $input );
}
} elseif ( 'dimension' === $type ) {
$input_safe = array();
// Loop over array and set errors.
foreach ( $input as $key => $value ) {
if ( ! empty( $value ) ) {
if ( ! is_numeric( $value ) && 'unit' !== $key ) {
add_settings_error( 'option-tree', 'invalid_dimension_' . $key, sprintf( $string_nums, '' . $key . '
', '' . $field_id . '
' ), 'error' );
} else {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
}
} elseif ( 'gallery' === $type ) {
$input_safe = '';
if ( '' !== trim( $input ) ) {
$input_safe = sanitize_text_field( $input );
}
} elseif ( 'google-fonts' === $type ) {
$input_safe = array();
// Loop over array.
foreach ( $input as $key => $value ) {
if ( '%key%' === $key ) {
continue;
}
foreach ( $value as $fk => $fvalue ) {
if ( is_array( $fvalue ) ) {
foreach ( $fvalue as $sk => $svalue ) {
$input_safe[ $key ][ $fk ][ $sk ] = sanitize_text_field( $svalue );
}
} else {
$input_safe[ $key ][ $fk ] = sanitize_text_field( $fvalue );
}
}
}
array_values( $input_safe );
} elseif ( 'link-color' === $type ) {
$input_safe = array();
// Loop over array and check for values.
if ( is_array( $input ) && ! empty( $input ) ) {
foreach ( $input as $key => $value ) {
if ( ! empty( $value ) ) {
$input_safe[ $key ] = ot_validate_setting( $input[ $key ], 'colorpicker', $field_id . '-' . $key );
}
}
}
array_filter( $input_safe );
} elseif ( 'measurement' === $type ) {
$input_safe = array();
foreach ( $input as $key => $value ) {
if ( ! empty( $value ) ) {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
} elseif ( 'numeric-slider' === $type ) {
$input_safe = '';
if ( ! empty( $input ) ) {
if ( ! is_numeric( $input ) ) {
add_settings_error( 'option-tree', 'invalid_numeric_slider', sprintf( $string_nums, '' . esc_html__( 'slider', 'option-tree' ) . '
', '' . $field_id . '
' ), 'error' );
} else {
$input_safe = sanitize_text_field( $input );
}
}
} elseif ( 'on-off' === $type ) {
$input_safe = '';
if ( ! empty( $input ) ) {
$input_safe = sanitize_text_field( $input );
}
} elseif ( 'radio' === $type || 'radio-image' === $type || 'select' === $type || 'sidebar-select' === $type ) {
$input_safe = '';
if ( ! empty( $input ) ) {
$input_safe = sanitize_text_field( $input );
}
} elseif ( 'spacing' === $type ) {
$input_safe = array();
// Loop over array and set errors.
foreach ( $input as $key => $value ) {
if ( ! empty( $value ) ) {
if ( ! is_numeric( $value ) && 'unit' !== $key ) {
add_settings_error( 'option-tree', 'invalid_spacing_' . $key, sprintf( $string_nums, '' . $key . '
', '' . $field_id . '
' ), 'error' );
} else {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
}
} elseif ( 'typography' === $type && isset( $input['font-color'] ) ) {
$input_safe = array();
// Loop over array and check for values.
foreach ( $input as $key => $value ) {
if ( 'font-color' === $key ) {
$input_safe[ $key ] = ot_validate_setting( $value, 'colorpicker', $field_id );
} else {
$input_safe[ $key ] = sanitize_text_field( $value );
}
}
} elseif ( 'upload' === $type ) {
$input_safe = filter_var( $input, FILTER_VALIDATE_INT );
if ( false === $input_safe && is_string( $input ) ) {
$input_safe = esc_url_raw( $input );
}
} elseif ( 'url' === $type ) {
$input_safe = '';
if ( ! empty( $input ) ) {
$input_safe = esc_url_raw( $input );
}
} else {
/* translators: %1$s: the calling function, %2$s the filter name, %3$s the option type, %4$s the version number */
$string_error = esc_html__( 'Notice: %1$s was called incorrectly. All stored data must be filtered through %2$s, the %3$s option type is not using this filter. This is required since version %4$s.', 'option-tree' );
// Log a user notice that things have changed since the last version.
add_settings_error( 'option-tree', 'ot_validate_setting_error', sprintf( $string_error, 'ot_validate_setting
', 'ot_validate_setting_input_safe
', '' . $type . '
', '2.7.0
' ), 'error' );
$input_safe = '';
/*
* We don't know what the setting type is, so fallback to `sanitize_textarea_field`
* on all values and do a best-effort sanitize of the user data before saving it.
*/
if ( ! is_object( $input ) ) {
// Contains an integer, float, string or boolean.
if ( is_scalar( $input ) ) {
$input_safe = sanitize_textarea_field( $input );
} else {
if ( ! function_exists( '_sanitize_recursive' ) ) {
/**
* Filter the array values recursively.
*
* @param array $values The value to sanitize.
*
* @return array
*/
function _sanitize_recursive( $values = array() ) {
$result = array();
foreach ( $values as $key => $value ) {
if ( ! is_object( $value ) ) {
if ( is_scalar( $value ) ) {
$result[ $key ] = sanitize_textarea_field( $value );
} else {
$result[ $key ] = _sanitize_recursive( $value );
}
}
}
return $result;
}
}
$input_safe = _sanitize_recursive( $input );
}
}
}
// WPML Register and Unregister strings.
if ( ! empty( $wmpl_id ) ) {
// Allow filtering on the WPML option types.
$single_string_types = apply_filters( 'ot_wpml_option_types', array( 'text', 'textarea', 'textarea-simple' ) );
if ( in_array( $type, $single_string_types, true ) ) {
if ( ! empty( $input_safe ) ) {
ot_wpml_register_string( $wmpl_id, $input_safe );
} else {
ot_wpml_unregister_string( $wmpl_id );
}
}
}
/**
* Filter to modify the validated setting field value.
*
* It's important to note that the filter does not have access to
* the original value and can only modify the validated input value.
* This is a breaking change as of version 2.7.0.
*
* @param mixed $input_safe The setting field value.
* @param string $type The setting field type.
* @param string $field_id The setting field ID.
*/
$input_safe = apply_filters( 'ot_after_validate_setting', $input_safe, $type, $field_id );
return $input_safe;
}
}
if ( ! function_exists( 'ot_admin_styles' ) ) {
/**
* Setup the default admin styles
*
* @access public
* @since 2.0
*/
function ot_admin_styles() {
global $wp_styles, $post;
// Execute styles before actions.
do_action( 'ot_admin_styles_before' );
// Load WP colorpicker.
wp_enqueue_style( 'wp-color-picker' );
// Load admin styles.
wp_enqueue_style( 'ot-admin-css', OT_URL . 'assets/css/ot-admin.css', false, OT_VERSION );
// Load the RTL stylesheet.
$wp_styles->add_data( 'ot-admin-css', 'rtl', true );
// Remove styles added by the Easy Digital Downloads plugin.
if ( isset( $post->post_type ) && 'post' === $post->post_type ) {
wp_dequeue_style( 'jquery-ui-css' );
}
/**
* Filter the screen IDs used to dequeue `jquery-ui-css`.
*
* @since 2.5.0
*
* @param array $screen_ids An array of screen IDs.
*/
$screen_ids = apply_filters(
'ot_dequeue_jquery_ui_css_screen_ids',
array(
'toplevel_page_ot-settings',
'optiontree_page_ot-documentation',
'appearance_page_ot-theme-options',
)
);
// Remove styles added by the WP Review plugin and any custom pages added through filtering.
if ( in_array( get_current_screen()->id, $screen_ids, true ) ) {
wp_dequeue_style( 'plugin_name-admin-ui-css' );
wp_dequeue_style( 'jquery-ui-css' );
}
// Execute styles after actions.
do_action( 'ot_admin_styles_after' );
}
}
if ( ! function_exists( 'ot_admin_scripts' ) ) {
/**
* Setup the default admin scripts.
*
* @uses add_thickbox() Include Thickbox for file uploads.
* @uses wp_enqueue_script() Add OptionTree scripts.
* @uses wp_localize_script() Used to include arbitrary Javascript data.
*
* @access public
* @since 2.0
*/
function ot_admin_scripts() {
// Execute scripts before actions.
do_action( 'ot_admin_scripts_before' );
if ( function_exists( 'wp_enqueue_media' ) ) {
// WP 3.5 Media Uploader.
wp_enqueue_media();
} else {
// Legacy Thickbox.
add_thickbox();
}
// Load jQuery-ui slider.
wp_enqueue_script( 'jquery-ui-slider' );
// Load jQuery-ui datepicker.
wp_enqueue_script( 'jquery-ui-datepicker' );
// Load WP colorpicker.
wp_enqueue_script( 'wp-color-picker' );
// Load Ace Editor for CSS Editing.
wp_enqueue_script( 'ace-editor', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js', null, '1.1.3', false );
// Load jQuery UI timepicker addon.
wp_enqueue_script( 'jquery-ui-timepicker', OT_URL . 'assets/js/vendor/jquery/jquery-ui-timepicker.js', array( 'jquery', 'jquery-ui-slider', 'jquery-ui-datepicker' ), '1.4.3', false );
// Load the post formats.
if ( true === OT_META_BOXES && true === OT_POST_FORMATS ) {
wp_enqueue_script( 'ot-postformats', OT_URL . 'assets/js/ot-postformats.js', array( 'jquery' ), '1.0.1', false );
}
// Load all the required scripts.
wp_enqueue_script( 'ot-admin-js', OT_URL . 'assets/js/ot-admin.js', array( 'jquery', 'jquery-ui-tabs', 'jquery-ui-sortable', 'jquery-ui-slider', 'wp-color-picker', 'ace-editor', 'jquery-ui-datepicker', 'jquery-ui-timepicker' ), OT_VERSION, false );
// Create localized JS array.
$localized_array = array(
'ajax' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'option_tree' ),
'upload_text' => apply_filters( 'ot_upload_text', __( 'Send to OptionTree', 'option-tree' ) ),
'remove_media_text' => esc_html__( 'Remove Media', 'option-tree' ),
'reset_agree' => esc_html__( 'Are you sure you want to reset back to the defaults?', 'option-tree' ),
'remove_no' => esc_html__( 'You can\'t remove this! But you can edit the values.', 'option-tree' ),
'remove_agree' => esc_html__( 'Are you sure you want to remove this?', 'option-tree' ),
'activate_layout_agree' => esc_html__( 'Are you sure you want to activate this layout?', 'option-tree' ),
'setting_limit' => esc_html__( 'Sorry, you can\'t have settings three levels deep.', 'option-tree' ),
'delete' => esc_html__( 'Delete Gallery', 'option-tree' ),
'edit' => esc_html__( 'Edit Gallery', 'option-tree' ),
'create' => esc_html__( 'Create Gallery', 'option-tree' ),
'confirm' => esc_html__( 'Are you sure you want to delete this Gallery?', 'option-tree' ),
'date_current' => esc_html__( 'Today', 'option-tree' ),
'date_time_current' => esc_html__( 'Now', 'option-tree' ),
'date_close' => esc_html__( 'Close', 'option-tree' ),
'replace' => esc_html__( 'Featured Image', 'option-tree' ),
'with' => esc_html__( 'Image', 'option-tree' ),
);
// Localized script attached to 'option_tree'.
wp_localize_script( 'ot-admin-js', 'option_tree', $localized_array );
// Execute scripts after actions.
do_action( 'ot_admin_scripts_after' );
}
}
if ( ! function_exists( 'ot_get_media_post_ID' ) ) {
/**
* Returns the ID of a custom post type by post_title.
*
* @return int
*
* @access public
* @since 2.0
* @updated 2.7.0
*/
function ot_get_media_post_ID() { // phpcs:ignore
// Option ID.
$option_id = 'ot_media_post_ID';
// Get the media post ID.
$post_ID = get_option( $option_id, false );
// Add $post_ID to the DB.
if ( false === $post_ID || empty( $post_ID ) || ! is_integer( $post_ID ) ) {
global $wpdb;
// Get the media post ID.
$post_ID = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts p WHERE p.post_title = %s AND p.post_type = %s AND p.post_status = %s", 'Media', 'option-tree', 'private' ) ); // phpcs:ignore
// Add to the DB.
if ( null !== $post_ID && 0 < $post_ID ) {
update_option( $option_id, $post_ID );
} else {
$post_ID = 0;
}
}
return $post_ID;
}
}
if ( ! function_exists( 'ot_create_media_post' ) ) {
/**
* Register custom post type & create the media post used to attach images.
*
* @access public
* @since 2.0
*/
function ot_create_media_post() {
register_post_type(
'option-tree',
array(
'labels' => array( 'name' => esc_html__( 'Option Tree', 'option-tree' ) ),
'public' => false,
'show_ui' => false,
'capability_type' => 'post',
'exclude_from_search' => true,
'hierarchical' => false,
'rewrite' => false,
'supports' => array( 'title', 'editor' ),
'can_export' => false,
'show_in_nav_menus' => false,
)
);
// Look for custom page.
$post_id = ot_get_media_post_ID();
// No post exists.
if ( 0 === $post_id ) {
// Insert the post into the database.
wp_insert_post(
array(
'post_title' => 'Media',
'post_name' => 'media',
'post_status' => 'private',
'post_type' => 'option-tree',
'comment_status' => 'closed',
'ping_status' => 'closed',
)
);
}
}
}
if ( ! function_exists( 'ot_default_settings' ) ) {
/**
* Setup default settings array.
*
* @access public
* @since 2.0
*/
function ot_default_settings() {
global $wpdb;
if ( ! get_option( ot_settings_id() ) ) {
$section_count = 0;
$settings_count = 0;
$settings = array();
$table_name = $wpdb->prefix . 'option_tree';
$find_table = wp_cache_get( 'find_table', 'option_tree' );
if ( false === $find_table ) {
$find_table = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ); // phpcs:ignore
wp_cache_set( 'find_table', $find_table, 'option_tree', 86400 );
}
if ( $find_table === $table_name ) {
$old_settings = wp_cache_get( 'old_settings', 'option_tree' );
if ( false === $old_settings ) {
$old_settings = $wpdb->get_results( "SELECT * FROM ${table_name} ORDER BY item_sort ASC" ); // phpcs:ignore
wp_cache_set( 'old_settings', $old_settings, 'option_tree', 86400 );
}
if ( ! $old_settings ) {
return;
}
foreach ( $old_settings as $setting ) {
// Heading is a section now.
if ( 'heading' === $setting->item_type ) {
// Add section to the sections array.
$settings['sections'][ $section_count ]['id'] = $setting->item_id;
$settings['sections'][ $section_count ]['title'] = $setting->item_title;
// Ssave the last section id to use in creating settings.
$section = $setting->item_id;
// Increment the section count.
$section_count++;
} else {
// Add setting to the settings array.
$settings['settings'][ $settings_count ]['id'] = $setting->item_id;
$settings['settings'][ $settings_count ]['label'] = $setting->item_title;
$settings['settings'][ $settings_count ]['desc'] = $setting->item_desc;
$settings['settings'][ $settings_count ]['section'] = $section;
$settings['settings'][ $settings_count ]['type'] = ot_map_old_option_types( $setting->item_type );
$settings['settings'][ $settings_count ]['std'] = '';
$settings['settings'][ $settings_count ]['class'] = '';
// Textarea rows.
$rows = '';
if ( in_array( $settings['settings'][ $settings_count ]['type'], array( 'css', 'javascript', 'textarea' ), true ) ) {
if ( (int) $setting->item_options > 0 ) {
$rows = (int) $setting->item_options;
} else {
$rows = 15;
}
}
$settings['settings'][ $settings_count ]['rows'] = $rows;
// Post type.
$post_type = '';
if ( in_array( $settings['settings'][ $settings_count ]['type'], array( 'custom-post-type-select', 'custom-post-type-checkbox' ), true ) ) {
if ( '' !== $setting->item_options ) {
$post_type = $setting->item_options;
} else {
$post_type = 'post';
}
}
$settings['settings'][ $settings_count ]['post_type'] = $post_type;
// Cchoices.
$choices = array();
if ( in_array( $settings['settings'][ $settings_count ]['type'], array( 'checkbox', 'radio', 'select' ), true ) ) {
if ( '' !== $setting->item_options ) {
$choices = ot_convert_string_to_array( $setting->item_options );
}
}
$settings['settings'][ $settings_count ]['choices'] = $choices;
$settings_count++;
}
}
// Make sure each setting has a section just in case.
if ( isset( $settings['sections'] ) && isset( $settings['settings'] ) ) {
foreach ( $settings['settings'] as $k => $setting ) {
if ( '' === $setting['section'] ) {
$settings['settings'][ $k ]['section'] = $settings['sections'][0]['id'];
}
}
}
}
// If array if not properly formed create fallback settings array.
if ( ! isset( $settings['sections'] ) || ! isset( $settings['settings'] ) ) {
$settings = array(
'sections' => array(
array(
'id' => 'general',
'title' => esc_html__( 'General', 'option-tree' ),
),
),
'settings' => array(
array(
'id' => 'sample_text',
'label' => esc_html__( 'Sample Text Field Label', 'option-tree' ),
'desc' => esc_html__( 'Description for the sample text field.', 'option-tree' ),
'section' => 'general',
'type' => 'text',
'std' => '',
'class' => '',
'rows' => '',
'post_type' => '',
'choices' => array(),
),
),
);
}
// Update the settings array.
update_option( ot_settings_id(), $settings );
// Get option tree array.
$options = get_option( ot_options_id() );
$options_safe = array();
// Validate options.
if ( is_array( $options ) ) {
foreach ( $settings['settings'] as $setting ) {
if ( isset( $options[ $setting['id'] ] ) ) {
$options_safe[ $setting['id'] ] = ot_validate_setting( wp_unslash( $options[ $setting['id'] ] ), $setting['type'], $setting['id'] );
}
}
// Execute the action hook and pass the theme options to it.
do_action( 'ot_before_theme_options_save', $options_safe );
// Update the option tree array.
update_option( ot_options_id(), $options_safe );
}
}
}
}
if ( ! function_exists( 'ot_save_css' ) ) {
/**
* Helper function to update the CSS option type after save.
*
* This function is called during the `ot_after_theme_options_save` hook,
* which is passed the currently stored options array.
*
* @param array $options The current stored options array.
*
* @access public
* @since 2.0
*/
function ot_save_css( $options ) {
// Grab a copy of the settings.
$settings = get_option( ot_settings_id() );
// Has settings.
if ( isset( $settings['settings'] ) ) {
// Loop through sections and insert CSS when needed.
foreach ( $settings['settings'] as $k => $setting ) {
// Is the CSS option type.
if ( isset( $setting['type'] ) && 'css' === $setting['type'] ) {
// Insert CSS into dynamic.css.
if ( isset( $options[ $setting['id'] ] ) && '' !== $options[ $setting['id'] ] ) {
ot_insert_css_with_markers( $setting['id'], $options[ $setting['id'] ] );
// Remove old CSS from dynamic.css.
} else {
ot_remove_old_css( $setting['id'] );
}
}
}
}
}
}
if ( ! function_exists( 'ot_import' ) ) {
/**
* Import before the screen is displayed.
*
* @access public
* @since 2.0
*/
function ot_import() {
// Check and verify import settings nonce.
if ( isset( $_POST['import_settings_nonce'] ) && wp_verify_nonce( $_POST['import_settings_nonce'], 'import_settings_form' ) ) { // phpcs:ignore
// Default message.
$message = 'failed';
$settings = isset( $_POST['import_settings'] ) ? ot_decode( sanitize_text_field( wp_unslash( $_POST['import_settings'] ) ) ) : array();
if ( is_array( $settings ) && ! empty( $settings ) ) {
$settings_safe = ot_validate_settings( $settings );
// Save & show success message.
if ( is_array( $settings_safe ) ) {
update_option( ot_settings_id(), $settings_safe );
$message = 'success';
}
}
// Redirect back to self.
wp_safe_redirect(
esc_url_raw(
add_query_arg(
array(
'action' => 'import-settings',
'message' => $message,
),
wp_get_referer()
)
)
);
exit;
}
// Check and verify import theme options data nonce.
if ( isset( $_POST['import_data_nonce'] ) && wp_verify_nonce( $_POST['import_data_nonce'], 'import_data_form' ) ) { // phpcs:ignore
// Default message.
$message = 'failed';
$options = isset( $_POST['import_data'] ) ? ot_decode( sanitize_text_field( wp_unslash( $_POST['import_data'] ) ) ) : array();
if ( $options ) {
$options_safe = array();
// Get settings array.
$settings = get_option( ot_settings_id() );
// Has options.
if ( is_array( $options ) ) {
// Validate options.
if ( is_array( $settings ) ) {
foreach ( $settings['settings'] as $setting ) {
if ( isset( $options[ $setting['id'] ] ) ) {
$options_safe[ $setting['id'] ] = ot_validate_setting( wp_unslash( $options[ $setting['id'] ] ), $setting['type'], $setting['id'] );
}
}
}
// Execute the action hook and pass the theme options to it.
do_action( 'ot_before_theme_options_save', $options_safe );
// Update the option tree array.
update_option( ot_options_id(), $options_safe );
$message = 'success';
}
}
// Redirect back to self.
wp_safe_redirect(
esc_url_raw(
add_query_arg(
array(
'action' => 'import-data',
'message' => $message,
),
wp_get_referer()
)
)
);
exit;
}
// Check and verify import layouts nonce.
if ( isset( $_POST['import_layouts_nonce'] ) && wp_verify_nonce( $_POST['import_layouts_nonce'], 'import_layouts_form' ) ) { // phpcs:ignore
// Default message.
$message = 'failed';
$layouts = isset( $_POST['import_layouts'] ) ? ot_decode( sanitize_text_field( wp_unslash( $_POST['import_layouts'] ) ) ) : array();
if ( $layouts ) {
// Get settings array.
$settings = get_option( ot_settings_id() );
// Has layouts.
if ( is_array( $layouts ) && ! empty( $layouts ) && ! empty( $layouts['active_layout'] ) ) {
$layouts_safe = array(
'active_layout' => esc_attr( $layouts['active_layout'] ),
);
// Validate options.
if ( is_array( $settings ) ) {
foreach ( $layouts as $key => $value ) {
if ( 'active_layout' === $key ) {
continue;
}
// Convert the options to an array.
$options = ot_decode( $value );
$options_safe = array();
foreach ( $settings['settings'] as $setting ) {
if ( isset( $options[ $setting['id'] ] ) ) {
$options_safe[ $setting['id'] ] = ot_validate_setting( wp_unslash( $options[ $setting['id'] ] ), $setting['type'], $setting['id'] );
}
}
// Store the sanitized values for later.
if ( $key === $layouts['active_layout'] ) {
$new_options_safe = $options_safe;
}
$layouts_safe[ $key ] = ot_encode( $options_safe );
}
}
// Update the option tree array with sanitized values.
if ( isset( $new_options_safe ) ) {
// Execute the action hook and pass the theme options to it.
do_action( 'ot_before_theme_options_save', $new_options_safe );
update_option( ot_options_id(), $new_options_safe );
}
// Update the option tree layouts array.
update_option( ot_layouts_id(), $layouts_safe );
$message = 'success';
}
}
// Redirect back to self.
wp_safe_redirect(
esc_url_raw(
add_query_arg(
array(
'action' => 'import-layouts',
'message' => $message,
),
wp_get_referer()
)
)
);
exit;
}
return false;
}
}
if ( ! function_exists( 'ot_export' ) ) {
/**
* Export before the screen is displayed.
*
* @return void
*
* @access public
* @since 2.0.8
*/
function ot_export() {
// Check and verify export settings file nonce.
if ( isset( $_POST['export_settings_file_nonce'] ) && wp_verify_nonce( $_POST['export_settings_file_nonce'], 'export_settings_file_form' ) ) { // phpcs:ignore
ot_export_php_settings_array();
}
}
}
if ( ! function_exists( 'ot_export_php_settings_array' ) ) {
/**
* Export the Theme Mode theme-options.php
*
* @access public
* @since 2.0.8
*/
function ot_export_php_settings_array() {
$content = '';
$build_settings = '';
$contextual_help = '';
$sections = '';
$settings = '';
$option_tree_settings = get_option( ot_settings_id(), array() );
/**
* Domain string helper.
*
* @param string $string A string.
* @return string
*/
function ot_i18n_string( $string ) {
if ( ! empty( $string ) && isset( $_POST['domain'] ) && ! empty( $_POST['domain'] ) ) { // phpcs:ignore
$domain = str_replace( ' ', '-', trim( sanitize_text_field( wp_unslash( $_POST['domain'] ) ) ) ); // phpcs:ignore
return "esc_html__( '$string', '$domain' )";
}
return "'$string'";
}
header( 'Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0' );
header( 'Pragma: no-cache ' );
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: attachment; filename="theme-options.php"' );
header( 'Content-Type: application/octet-stream' );
header( 'Content-Transfer-Encoding: binary' );
// Build contextual help content.
if ( isset( $option_tree_settings['contextual_help']['content'] ) ) {
$help = '';
foreach ( $option_tree_settings['contextual_help']['content'] as $value ) {
$_id = isset( $value['id'] ) ? $value['id'] : '';
$_title = ot_i18n_string( isset( $value['title'] ) ? str_replace( "'", "\'", $value['title'] ) : '' );
$_content = ot_i18n_string( isset( $value['content'] ) ? html_entity_decode( str_replace( "'", "\'", $value['content'] ) ) : '' );
$help .= "
array(
'id' => '$_id',
'title' => $_title,
'content' => $_content,
),";
}
$contextual_help = "
'content' => array($help
),";
}
// Build contextual help sidebar.
if ( isset( $option_tree_settings['contextual_help']['sidebar'] ) ) {
$_sidebar = ot_i18n_string( html_entity_decode( str_replace( "'", "\'", $option_tree_settings['contextual_help']['sidebar'] ) ) );
$contextual_help .= "
'sidebar' => $_sidebar,";
}
// Check that $contexual_help has a value and add to $build_settings.
if ( '' !== $contextual_help ) {
$build_settings .= "
'contextual_help' => array($contextual_help
),";
}
// Build sections.
if ( isset( $option_tree_settings['sections'] ) ) {
foreach ( $option_tree_settings['sections'] as $value ) {
$_id = isset( $value['id'] ) ? $value['id'] : '';
$_title = ot_i18n_string( isset( $value['title'] ) ? str_replace( "'", "\'", $value['title'] ) : '' );
$sections .= "
array(
'id' => '$_id',
'title' => $_title,
),";
}
}
// Check that $sections has a value and add to $build_settings.
if ( '' !== $sections ) {
$build_settings .= "
'sections' => array($sections
)";
}
/* build settings */
if ( isset( $option_tree_settings['settings'] ) ) {
foreach ( $option_tree_settings['settings'] as $value ) {
$_id = isset( $value['id'] ) ? $value['id'] : '';
$_label = ot_i18n_string( isset( $value['label'] ) ? str_replace( "'", "\'", $value['label'] ) : '' );
$_desc = ot_i18n_string( isset( $value['desc'] ) ? str_replace( "'", "\'", $value['desc'] ) : '' );
$_std = isset( $value['std'] ) ? str_replace( "'", "\'", $value['std'] ) : '';
$_type = isset( $value['type'] ) ? $value['type'] : '';
$_section = isset( $value['section'] ) ? $value['section'] : '';
$_rows = isset( $value['rows'] ) ? $value['rows'] : '';
$_post_type = isset( $value['post_type'] ) ? $value['post_type'] : '';
$_taxonomy = isset( $value['taxonomy'] ) ? $value['taxonomy'] : '';
$_min_max_step = isset( $value['min_max_step'] ) ? $value['min_max_step'] : '';
$_class = isset( $value['class'] ) ? $value['class'] : '';
$_condition = isset( $value['condition'] ) ? $value['condition'] : '';
$_operator = isset( $value['operator'] ) ? $value['operator'] : '';
$choices = '';
if ( isset( $value['choices'] ) && ! empty( $value['choices'] ) ) {
foreach ( $value['choices'] as $choice ) {
$_choice_value = isset( $choice['value'] ) ? str_replace( "'", "\'", $choice['value'] ) : '';
$_choice_label = ot_i18n_string( isset( $choice['label'] ) ? str_replace( "'", "\'", $choice['label'] ) : '' );
$_choice_src = isset( $choice['src'] ) ? str_replace( "'", "\'", $choice['src'] ) : '';
$choices .= "
array(
'value' => '$_choice_value',
'label' => $_choice_label,
'src' => '$_choice_src',
),";
}
$choices = "
'choices' => array($choices
),";
}
$std = "'$_std'";
if ( is_array( $_std ) ) {
$std_array = array();
foreach ( $_std as $_sk => $_sv ) {
$std_array[] = "'$_sk' => '$_sv',";
}
$std = 'array(
' . implode( ",\n", $std_array ) . '
)';
}
$setting_settings = '';
if ( isset( $value['settings'] ) && ! empty( $value['settings'] ) ) {
foreach ( $value['settings'] as $setting ) {
$_setting_id = isset( $setting['id'] ) ? $setting['id'] : '';
$_setting_label = ot_i18n_string( isset( $setting['label'] ) ? str_replace( "'", "\'", $setting['label'] ) : '' );
$_setting_desc = ot_i18n_string( isset( $setting['desc'] ) ? str_replace( "'", "\'", $setting['desc'] ) : '' );
$_setting_std = isset( $setting['std'] ) ? $setting['std'] : '';
$_setting_type = isset( $setting['type'] ) ? $setting['type'] : '';
$_setting_rows = isset( $setting['rows'] ) ? $setting['rows'] : '';
$_setting_post_type = isset( $setting['post_type'] ) ? $setting['post_type'] : '';
$_setting_taxonomy = isset( $setting['taxonomy'] ) ? $setting['taxonomy'] : '';
$_setting_min_max_step = isset( $setting['min_max_step'] ) ? $setting['min_max_step'] : '';
$_setting_class = isset( $setting['class'] ) ? $setting['class'] : '';
$_setting_condition = isset( $setting['condition'] ) ? $setting['condition'] : '';
$_setting_operator = isset( $setting['operator'] ) ? $setting['operator'] : '';
$setting_choices = '';
if ( isset( $setting['choices'] ) && ! empty( $setting['choices'] ) ) {
foreach ( $setting['choices'] as $setting_choice ) {
$_setting_choice_value = isset( $setting_choice['value'] ) ? $setting_choice['value'] : '';
$_setting_choice_label = ot_i18n_string( isset( $setting_choice['label'] ) ? str_replace( "'", "\'", $setting_choice['label'] ) : '' );
$_setting_choice_src = isset( $setting_choice['src'] ) ? str_replace( "'", "\'", $setting_choice['src'] ) : '';
$setting_choices .= "
array(
'value' => '$_setting_choice_value',
'label' => $_setting_choice_label,
'src' => '$_setting_choice_src',
),";
}
$setting_choices = "
'choices' => array($setting_choices
),";
}
$setting_std = "'$_setting_std'";
if ( is_array( $_setting_std ) ) {
$setting_std_array = array();
foreach ( $_setting_std as $_ssk => $_ssv ) {
$setting_std_array[] = "'$_ssk' => '$_ssv'";
}
$setting_std = 'array(
' . implode( ",\n", $setting_std_array ) . '
)';
}
$setting_settings .= "
array(
'id' => '$_setting_id',
'label' => $_setting_label,
'desc' => $_setting_desc,
'std' => $setting_std,
'type' => '$_setting_type',
'rows' => '$_setting_rows',
'post_type' => '$_setting_post_type',
'taxonomy' => '$_setting_taxonomy',
'min_max_step' => '$_setting_min_max_step',
'class' => '$_setting_class',
'condition' => '$_setting_condition',
'operator' => '$_setting_operator',$setting_choices
),";
}
$setting_settings = "
'settings' => array( $setting_settings
),";
}
$settings .= "
array(
'id' => '$_id',
'label' => $_label,
'desc' => $_desc,
'std' => $std,
'type' => '$_type',
'section' => '$_section',
'rows' => '$_rows',
'post_type' => '$_post_type',
'taxonomy' => '$_taxonomy',
'min_max_step' => '$_min_max_step',
'class' => '$_class',
'condition' => '$_condition',
'operator' => '$_operator',$choices$setting_settings
),";
}
}
// Check that $sections has a value and add to $build_settings.
if ( '' !== $settings ) {
$build_settings .= ",
'settings' => array($settings
)";
}
$content .= " 'save-settings',
'message' => $message,
),
wp_get_referer()
)
)
);
exit;
}
return false;
}
}
if ( ! function_exists( 'ot_wpml_unregister' ) ) {
/**
* Unregister WPML strings based on settings changing.
*
* @param array $settings The array of settings.
*
* @access public
* @since 2.7.0
*/
function ot_wpml_unregister( $settings = array() ) {
// WPML unregister ID's that have been removed.
if ( function_exists( 'icl_unregister_string' ) ) {
$current = get_option( ot_settings_id() );
$options = get_option( ot_options_id() );
if ( isset( $current['settings'] ) ) {
// Empty ID array.
$new_ids = array();
// Build the WPML IDs array.
foreach ( $settings['settings'] as $setting ) {
if ( $setting['id'] ) {
$new_ids[] = $setting['id'];
}
}
// Remove missing IDs from WPML.
foreach ( $current['settings'] as $current_setting ) {
if ( ! in_array( $current_setting['id'], $new_ids, true ) ) {
if ( ! empty( $options[ $current_setting['id'] ] ) && in_array( $current_setting['type'], array( 'list-item', 'slider' ), true ) ) {
foreach ( $options[ $current_setting['id'] ] as $key => $value ) {
foreach ( $value as $ckey => $cvalue ) {
ot_wpml_unregister_string( $current_setting['id'] . '_' . $ckey . '_' . $key );
}
}
} elseif ( ! empty( $options[ $current_setting['id'] ] ) && 'social-icons' === $current_setting['type'] ) {
foreach ( $options[ $current_setting['id'] ] as $key => $value ) {
foreach ( $value as $ckey => $cvalue ) {
ot_wpml_unregister_string( $current_setting['id'] . '_' . $ckey . '_' . $key );
}
}
} else {
ot_wpml_unregister_string( $current_setting['id'] );
}
}
}
}
}
}
}
if ( ! function_exists( 'ot_validate_settings' ) ) {
/**
* Helper function to validate all settings.
*
* This includes the `sections`, `settings`, and `contextual_help` arrays.
*
* @param array $settings The array of settings.
*
* @return array
*
* @access public
* @since 2.7.0
*/
function ot_validate_settings( $settings = array() ) {
// Store the validated settings.
$settings_safe = array();
// Validate sections.
if ( isset( $settings['sections'] ) ) {
// Fix numeric keys since drag & drop will change them.
$settings['sections'] = array_values( $settings['sections'] );
// Loop through sections.
foreach ( $settings['sections'] as $k => $section ) {
// Skip if missing values.
if ( ( ! isset( $section['title'] ) && ! isset( $section['id'] ) ) || ( '' === $section['title'] && '' === $section['id'] ) ) {
continue;
}
// Validate label.
if ( '' !== $section['title'] ) {
$settings_safe['sections'][ $k ]['title'] = wp_kses_post( $section['title'] );
}
// Missing title set to unfiltered ID.
if ( ! isset( $section['title'] ) || '' === $section['title'] ) {
$settings_safe['sections'][ $k ]['title'] = wp_kses_post( $section['id'] );
// Missing ID set to title.
} elseif ( ! isset( $section['id'] ) || '' === $section['id'] ) {
$settings_safe['id'] = wp_kses_post( $section['title'] );
}
// Sanitize ID once everything has been checked first.
$settings_safe['sections'][ $k ]['id'] = ot_sanitize_option_id( wp_kses_post( $section['id'] ) );
}
}
// Validate settings by looping over array as many times as it takes.
if ( isset( $settings['settings'] ) ) {
$settings_safe['settings'] = ot_validate_settings_array( $settings['settings'] );
}
// Validate contextual_help.
if ( isset( $settings['contextual_help']['content'] ) ) {
// Fix numeric keys since drag & drop will change them.
$settings['contextual_help']['content'] = array_values( $settings['contextual_help']['content'] );
// Loop through content.
foreach ( $settings['contextual_help']['content'] as $k => $content ) {
// Skip if missing values.
if ( ( ! isset( $content['title'] ) && ! isset( $content['id'] ) ) || ( '' === $content['title'] && '' === $content['id'] ) ) {
continue;
}
// Validate label.
if ( '' !== $content['title'] ) {
$settings_safe['contextual_help']['content'][ $k ]['title'] = wp_kses_post( $content['title'] );
}
// Missing title set to unfiltered ID.
if ( ! isset( $content['title'] ) || '' === $content['title'] ) {
$settings_safe['contextual_help']['content'][ $k ]['title'] = wp_kses_post( $content['id'] );
// Missing ID set to title.
} elseif ( ! isset( $content['id'] ) || '' === $content['id'] ) {
$content['id'] = wp_kses_post( $content['title'] );
}
// Sanitize ID once everything has been checked first.
$settings_safe['contextual_help']['content'][ $k ]['id'] = ot_sanitize_option_id( wp_kses_post( $content['id'] ) );
// Validate textarea description.
if ( isset( $content['content'] ) ) {
$settings_safe['contextual_help']['content'][ $k ]['content'] = wp_kses_post( $content['content'] );
}
}
}
// Validate contextual_help sidebar.
if ( isset( $settings['contextual_help']['sidebar'] ) ) {
$settings_safe['contextual_help']['sidebar'] = wp_kses_post( $settings['contextual_help']['sidebar'] );
}
return $settings_safe;
}
}
if ( ! function_exists( 'ot_validate_settings_array' ) ) {
/**
* Validate a settings array before save.
*
* This function will loop over a settings array as many
* times as it takes to validate every sub setting.
*
* @param array $settings The array of settings.
* @return array
*
* @access public
* @since 2.0
* @updated 2.7.0
*/
function ot_validate_settings_array( $settings = array() ) {
// Field types mapped to their sanitize function.
$field_types = array(
'label' => 'wp_kses_post',
'id' => 'ot_sanitize_option_id',
'type' => 'sanitize_text_field',
'desc' => 'wp_kses_post',
'settings' => 'ot_validate_settings_array',
'choices' => array(
'label' => 'wp_kses_post',
'value' => 'sanitize_text_field',
'src' => 'sanitize_text_field',
),
'std' => 'sanitize_text_field',
'rows' => 'absint',
'post_type' => 'sanitize_text_field',
'taxonomy' => 'sanitize_text_field',
'min_max_step' => 'sanitize_text_field',
'class' => 'sanitize_text_field',
'condition' => 'sanitize_text_field',
'operator' => 'sanitize_text_field',
'section' => 'sanitize_text_field',
);
// Store the validated settings.
$settings_safe = array();
// Validate settings.
if ( 0 < count( $settings ) ) {
// Fix numeric keys since drag & drop will change them.
$settings = array_values( $settings );
// Loop through settings.
foreach ( $settings as $sk => $setting ) {
foreach ( $setting as $fk => $field ) {
if ( isset( $field_types[ $fk ] ) ) {
if ( 'choices' === $fk ) {
foreach ( $field as $ck => $choice ) {
foreach ( $choice as $vk => $value ) {
$settings_safe[ $sk ][ $fk ][ $ck ][ $vk ] = call_user_func( $field_types[ $fk ][ $vk ], $value );
}
}
} elseif ( 'std' === $fk && is_array( $field ) ) {
$callback = $field_types[ $fk ];
$array_map = function( $item ) use ( $array_map, $callback ) {
return is_array( $item ) ? array_map( $array_map, $item ) : call_user_func( $callback, $item );
};
$settings_safe[ $sk ][ $fk ] = array_map( $array_map, $field );
} else {
$sanitized = call_user_func( $field_types[ $fk ], $field );
if ( 'rows' === $fk && 0 === $sanitized ) {
$sanitized = '';
}
$settings_safe[ $sk ][ $fk ] = $sanitized;
}
}
}
}
}
return $settings_safe;
}
}
if ( ! function_exists( 'ot_modify_layouts' ) ) {
/**
* Save layouts array before the screen is displayed.
*
* @return bool Returns false or redirects.
*
* @access public
* @since 2.0
*/
function ot_modify_layouts() {
// Check and verify modify layouts nonce.
if ( isset( $_POST['option_tree_modify_layouts_nonce'] ) && wp_verify_nonce( $_POST['option_tree_modify_layouts_nonce'], 'option_tree_modify_layouts_form' ) ) { // phpcs:ignore
// Previous layouts value.
$option_tree_layouts = get_option( ot_layouts_id() );
// New layouts value.
$layouts = isset( $_POST[ ot_layouts_id() ] ) ? $_POST[ ot_layouts_id() ] : ''; // phpcs:ignore
// Rebuild layout array.
$rebuild = array();
// Validate layouts.
if ( is_array( $layouts ) && ! empty( $layouts ) ) {
// Setup active layout.
if ( isset( $layouts['active_layout'] ) && ! empty( $layouts['active_layout'] ) ) {
$rebuild['active_layout'] = $layouts['active_layout'];
}
// Add new and overwrite active layout.
if ( isset( $layouts['_add_new_layout_'] ) && ! empty( $layouts['_add_new_layout_'] ) ) {
$rebuild['active_layout'] = ot_sanitize_layout_id( $layouts['_add_new_layout_'] );
$rebuild[ $rebuild['active_layout'] ] = ot_encode( get_option( ot_options_id(), array() ) );
}
$first_layout = '';
// Loop through layouts.
foreach ( $layouts as $key => $layout ) {
// Skip over active layout key.
if ( 'active_layout' === $key ) {
continue;
}
// Check if the key exists then set value.
if ( isset( $option_tree_layouts[ $key ] ) && ! empty( $option_tree_layouts[ $key ] ) ) {
$rebuild[ $key ] = $option_tree_layouts[ $key ];
if ( '' === $first_layout ) {
$first_layout = $key;
}
}
}
if ( isset( $rebuild['active_layout'] ) && ! isset( $rebuild[ $rebuild['active_layout'] ] ) && ! empty( $first_layout ) ) {
$rebuild['active_layout'] = $first_layout;
}
}
// Default message.
$message = 'failed';
// Save & show success message.
if ( is_array( $rebuild ) && 1 < count( $rebuild ) ) {
$options = ot_decode( $rebuild[ $rebuild['active_layout'] ] );
if ( $options ) {
$options_safe = array();
// Get settings array.
$settings = get_option( ot_settings_id() );
// Has options.
if ( is_array( $options ) ) {
// Validate options.
if ( is_array( $settings ) ) {
foreach ( $settings['settings'] as $setting ) {
if ( isset( $options[ $setting['id'] ] ) ) {
$options_safe[ $setting['id'] ] = ot_validate_setting( wp_unslash( $options[ $setting['id'] ] ), $setting['type'], $setting['id'] );
}
}
}
// Execute the action hook and pass the theme options to it.
do_action( 'ot_before_theme_options_save', $options_safe );
update_option( ot_options_id(), $options_safe );
}
}
// Rebuild the layouts.
update_option( ot_layouts_id(), $rebuild );
// Change message.
$message = 'success';
} elseif ( 1 >= count( $rebuild ) ) {
// Delete layouts option.
delete_option( ot_layouts_id() );
// Change message.
$message = 'deleted';
}
// Redirect.
if ( isset( $_REQUEST['page'] ) && apply_filters( 'ot_theme_options_menu_slug', 'ot-theme-options' ) === $_REQUEST['page'] ) {
$query_args = esc_url_raw(
add_query_arg(
array(
'settings-updated' => 'layout',
),
remove_query_arg(
array(
'action',
'message',
),
wp_get_referer()
)
)
);
} else {
$query_args = esc_url_raw(
add_query_arg(
array(
'action' => 'save-layouts',
'message' => $message,
),
wp_get_referer()
)
);
}
wp_safe_redirect( $query_args );
exit;
}
return false;
}
}
if ( ! function_exists( 'ot_alert_message' ) ) {
/**
* Helper function to display alert messages.
*
* @param array $page Page array.
* @return mixed
*
* @access public
* @since 2.0
*/
function ot_alert_message( $page = array() ) {
if ( empty( $page ) ) {
return false;
}
$before = apply_filters( 'ot_before_page_messages', '', $page );
if ( $before ) {
return $before;
}
$action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : ''; // phpcs:ignore
$message = isset( $_REQUEST['message'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['message'] ) ) : ''; // phpcs:ignore
$updated = isset( $_REQUEST['settings-updated'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['settings-updated'] ) ) : ''; // phpcs:ignore
if ( 'save-settings' === $action ) {
if ( 'success' === $message ) {
return '' . esc_html__( 'Settings updated.', 'option-tree' ) . '
' . esc_html__( 'Settings could not be saved.', 'option-tree' ) . '
' . esc_html__( 'Settings Imported.', 'option-tree' ) . '
' . esc_html__( 'Settings could not be imported.', 'option-tree' ) . '
' . esc_html__( 'Data Imported.', 'option-tree' ) . '
' . esc_html__( 'Data could not be imported.', 'option-tree' ) . '
' . esc_html__( 'Layouts Imported.', 'option-tree' ) . '
' . esc_html__( 'Layouts could not be imported.', 'option-tree' ) . '
' . esc_html__( 'Layouts Updated.', 'option-tree' ) . '
' . esc_html__( 'Layouts could not be updated.', 'option-tree' ) . '
' . esc_html__( 'Layouts have been deleted.', 'option-tree' ) . '
' . esc_html__( 'Layout activated.', 'option-tree' ) . '
' . $page['reset_message'] . '
' . $page['updated_message'] . '
http:// or https://
' ),
'type' => 'text',
),
),
$field_id
);
return $settings;
}
}
if ( ! function_exists( 'ot_insert_css_with_markers' ) ) {
/**
* Inserts CSS with field_id markers.
*
* Inserts CSS into a dynamic.css file, placing it between
* BEGIN and END field_id markers. Replaces existing marked info,
* but still retains surrounding data.
*
* @param string $field_id The CSS option field ID.
* @param string $insertion The current option_tree array.
* @param bool $meta Whether or not the value is stored in meta.
* @return bool True on write success, false on failure.
*
* @access public
* @since 1.1.8
* @updated 2.5.3
*/
function ot_insert_css_with_markers( $field_id = '', $insertion = '', $meta = false ) {
// Missing $field_id or $insertion exit early.
if ( '' === $field_id || '' === $insertion ) {
return;
}
// Path to the dynamic.css file.
$filepath = get_stylesheet_directory() . '/dynamic.css';
if ( is_multisite() ) {
$multisite_filepath = get_stylesheet_directory() . '/dynamic-' . get_current_blog_id() . '.css';
if ( file_exists( $multisite_filepath ) ) {
$filepath = $multisite_filepath;
}
}
// Allow filter on path.
$filepath = apply_filters( 'css_option_file_path', $filepath, $field_id );
// Grab a copy of the paths array.
$ot_css_file_paths = get_option( 'ot_css_file_paths', array() );
if ( is_multisite() ) {
$ot_css_file_paths = get_blog_option( get_current_blog_id(), 'ot_css_file_paths', $ot_css_file_paths );
}
// Set the path for this field.
$ot_css_file_paths[ $field_id ] = $filepath;
/* update the paths */
if ( is_multisite() ) {
update_blog_option( get_current_blog_id(), 'ot_css_file_paths', $ot_css_file_paths );
} else {
update_option( 'ot_css_file_paths', $ot_css_file_paths );
}
// Remove CSS from file, but ensure the file is actually CSS first.
$file_parts = explode( '.', basename( $filepath ) );
$file_ext = end( $file_parts );
if ( is_writeable( $filepath ) && 'css' === $file_ext ) {
$insertion = ot_normalize_css( $insertion );
$regex = '/{{([a-zA-Z0-9\_\-\#\|\=]+)}}/';
$marker = $field_id;
// Match custom CSS.
preg_match_all( $regex, $insertion, $matches );
// Loop through CSS.
foreach ( $matches[0] as $option ) {
$value = '';
$option_array = explode( '|', str_replace( array( '{{', '}}' ), '', $option ) );
$option_id = isset( $option_array[0] ) ? $option_array[0] : '';
$option_key = isset( $option_array[1] ) ? $option_array[1] : '';
$option_type = ot_get_option_type_by_id( $option_id );
$fallback = '';
// Get the meta array value.
if ( $meta ) {
global $post;
$value = get_post_meta( $post->ID, $option_id, true );
// Get the options array value.
} else {
$options = get_option( ot_options_id() );
if ( isset( $options[ $option_id ] ) ) {
$value = $options[ $option_id ];
}
}
// This in an array of values.
if ( is_array( $value ) ) {
if ( empty( $option_key ) ) {
// Measurement.
if ( 'measurement' === $option_type ) {
$unit = ! empty( $value[1] ) ? $value[1] : 'px';
// Set $value with measurement properties.
if ( isset( $value[0] ) && strlen( $value[0] ) > 0 ) {
$value = $value[0] . $unit;
}
// Border.
} elseif ( 'border' === $option_type ) {
$border = array();
$unit = ! empty( $value['unit'] ) ? $value['unit'] : 'px';
if ( isset( $value['width'] ) && strlen( $value['width'] ) > 0 ) {
$border[] = $value['width'] . $unit;
}
if ( ! empty( $value['style'] ) ) {
$border[] = $value['style'];
}
if ( ! empty( $value['color'] ) ) {
$border[] = $value['color'];
}
// Set $value with border properties or empty string.
$value = ! empty( $border ) ? implode( ' ', $border ) : '';
// Box Shadow.
} elseif ( 'box-shadow' === $option_type ) {
$value_safe = array();
foreach ( $value as $val ) {
if ( ! empty( $val ) ) {
$value_safe[] = $val;
}
}
// Set $value with box-shadow properties or empty string.
$value = ! empty( $value_safe ) ? implode( ' ', $value_safe ) : '';
// Dimension.
} elseif ( 'dimension' === $option_type ) {
$dimension = array();
$unit = ! empty( $value['unit'] ) ? $value['unit'] : 'px';
if ( isset( $value['width'] ) && strlen( $value['width'] ) > 0 ) {
$dimension[] = $value['width'] . $unit;
}
if ( isset( $value['height'] ) && strlen( $value['height'] ) > 0 ) {
$dimension[] = $value['height'] . $unit;
}
// Set $value with dimension properties or empty string.
$value = ! empty( $dimension ) ? implode( ' ', $dimension ) : '';
// Spacing.
} elseif ( 'spacing' === $option_type ) {
$spacing = array();
$unit = ! empty( $value['unit'] ) ? $value['unit'] : 'px';
if ( isset( $value['top'] ) && strlen( $value['top'] ) > 0 ) {
$spacing[] = $value['top'] . $unit;
}
if ( isset( $value['right'] ) && strlen( $value['right'] ) > 0 ) {
$spacing[] = $value['right'] . $unit;
}
if ( isset( $value['bottom'] ) && strlen( $value['bottom'] ) > 0 ) {
$spacing[] = $value['bottom'] . $unit;
}
if ( isset( $value['left'] ) && strlen( $value['left'] ) > 0 ) {
$spacing[] = $value['left'] . $unit;
}
// Set $value with spacing properties or empty string.
$value = ! empty( $spacing ) ? implode( ' ', $spacing ) : '';
// Typography.
} elseif ( 'typography' === $option_type ) {
$font = array();
if ( ! empty( $value['font-color'] ) ) {
$font[] = 'color: ' . $value['font-color'] . ';';
}
if ( ! empty( $value['font-family'] ) ) {
foreach ( ot_recognized_font_families( $marker ) as $key => $v ) {
if ( $key === $value['font-family'] ) {
$font[] = 'font-family: ' . $v . ';';
}
}
}
if ( ! empty( $value['font-size'] ) ) {
$font[] = 'font-size: ' . $value['font-size'] . ';';
}
if ( ! empty( $value['font-style'] ) ) {
$font[] = 'font-style: ' . $value['font-style'] . ';';
}
if ( ! empty( $value['font-variant'] ) ) {
$font[] = 'font-variant: ' . $value['font-variant'] . ';';
}
if ( ! empty( $value['font-weight'] ) ) {
$font[] = 'font-weight: ' . $value['font-weight'] . ';';
}
if ( ! empty( $value['letter-spacing'] ) ) {
$font[] = 'letter-spacing: ' . $value['letter-spacing'] . ';';
}
if ( ! empty( $value['line-height'] ) ) {
$font[] = 'line-height: ' . $value['line-height'] . ';';
}
if ( ! empty( $value['text-decoration'] ) ) {
$font[] = 'text-decoration: ' . $value['text-decoration'] . ';';
}
if ( ! empty( $value['text-transform'] ) ) {
$font[] = 'text-transform: ' . $value['text-transform'] . ';';
}
// Set $value with font properties or empty string.
$value = ! empty( $font ) ? implode( "\n", $font ) : '';
// Background.
} elseif ( 'background' === $option_type ) {
$bg = array();
if ( ! empty( $value['background-color'] ) ) {
$bg[] = $value['background-color'];
}
if ( ! empty( $value['background-image'] ) ) {
// If an attachment ID is stored here fetch its URL and replace the value.
if ( wp_attachment_is_image( $value['background-image'] ) ) {
$attachment_data = wp_get_attachment_image_src( $value['background-image'], 'original' );
// Check for attachment data.
if ( $attachment_data ) {
$value['background-image'] = $attachment_data[0];
}
}
$bg[] = 'url("' . $value['background-image'] . '")';
}
if ( ! empty( $value['background-repeat'] ) ) {
$bg[] = $value['background-repeat'];
}
if ( ! empty( $value['background-attachment'] ) ) {
$bg[] = $value['background-attachment'];
}
if ( ! empty( $value['background-position'] ) ) {
$bg[] = $value['background-position'];
}
if ( ! empty( $value['background-size'] ) ) {
$size = $value['background-size'];
}
// Set $value with background properties or empty string.
$value = ! empty( $bg ) ? 'background: ' . implode( ' ', $bg ) . ';' : '';
if ( isset( $size ) ) {
if ( ! empty( $bg ) ) {
$value .= apply_filters( 'ot_insert_css_with_markers_bg_size_white_space', "\n\x20\x20", $option_id );
}
$value .= "background-size: $size;";
}
}
} elseif ( ! empty( $value[ $option_key ] ) ) {
$value = $value[ $option_key ];
}
}
// If an attachment ID is stored here fetch its URL and replace the value.
if ( 'upload' === $option_type && wp_attachment_is_image( $value ) ) {
$attachment_data = wp_get_attachment_image_src( $value, 'original' );
// Check for attachment data.
if ( $attachment_data ) {
$value = $attachment_data[0];
}
}
// Attempt to fallback when `$value` is empty.
if ( empty( $value ) ) {
// We're trying to access a single array key.
if ( ! empty( $option_key ) ) {
// Link Color `inherit`.
if ( 'link-color' === $option_type ) {
$fallback = 'inherit';
}
} else {
// Border.
if ( 'border' === $option_type ) {
$fallback = 'inherit';
}
// Box Shadow.
if ( 'box-shadow' === $option_type ) {
$fallback = 'none';
}
// Colorpicker.
if ( 'colorpicker' === $option_type ) {
$fallback = 'inherit';
}
// Colorpicker Opacity.
if ( 'colorpicker-opacity' === $option_type ) {
$fallback = 'inherit';
}
}
/**
* Filter the `dynamic.css` fallback value.
*
* @since 2.5.3
*
* @param string $fallback The default CSS fallback value.
* @param string $option_id The option ID.
* @param string $option_type The option type.
* @param string $option_key The option array key.
*/
$fallback = apply_filters( 'ot_insert_css_with_markers_fallback', $fallback, $option_id, $option_type, $option_key );
}
// Let's fallback!
if ( ! empty( $fallback ) ) {
$value = $fallback;
}
// Filter the CSS.
$value = apply_filters( 'ot_insert_css_with_markers_value', $value, $option_id );
// Insert CSS, even if the value is empty.
$insertion = stripslashes( str_replace( $option, $value, $insertion ) );
}
// Can't write to the file so we error out.
if ( ! is_writable( $filepath ) ) {
/* translators: %s: file path */
$string = esc_html__( 'Unable to write to file %s.', 'option-tree' );
add_settings_error( 'option-tree', 'dynamic_css', sprintf( $string, '' . $filepath . '
' ), 'error' );
return false;
}
// Open file.
$f = @fopen( $filepath, 'w' ); // phpcs:ignore
// Can't write to the file return false.
if ( ! $f ) {
/* translators: %s: file path */
$string = esc_html__( 'Unable to open the %s file in write mode.', 'option-tree' );
add_settings_error( 'option-tree', 'dynamic_css', sprintf( $string, '' . $filepath . '
' ), 'error' );
return false;
}
// Create array from the lines of code.
$markerdata = explode( "\n", implode( '', file( $filepath ) ) );
$searching = true;
$foundit = false;
// Has array of lines.
if ( ! empty( $markerdata ) ) {
// Foreach line of code.
foreach ( $markerdata as $n => $markerline ) {
// Found begining of marker, set $searching to false.
if ( "/* BEGIN {$marker} */" === $markerline ) {
$searching = false;
}
// Keep searching each line of CSS.
if ( true === $searching ) {
if ( $n + 1 < count( $markerdata ) ) {
fwrite( $f, "{$markerline}\n" ); // phpcs:ignore
} else {
fwrite( $f, "{$markerline}" ); // phpcs:ignore
}
}
// Found end marker write code.
if ( "/* END {$marker} */" === $markerline ) {
fwrite( $f, "/* BEGIN {$marker} */\n" ); // phpcs:ignore
fwrite( $f, "{$insertion}\n" ); // phpcs:ignore
fwrite( $f, "/* END {$marker} */\n" ); // phpcs:ignore
$searching = true;
$foundit = true;
}
}
}
// Nothing inserted, write code. DO IT, DO IT!
if ( ! $foundit ) {
fwrite( $f, "/* BEGIN {$marker} */\n" ); // phpcs:ignore
fwrite( $f, "{$insertion}\n" ); // phpcs:ignore
fwrite( $f, "/* END {$marker} */\n" ); // phpcs:ignore
}
// Close file.
fclose( $f ); // phpcs:ignore
return true;
}
return false;
}
}
if ( ! function_exists( 'ot_remove_old_css' ) ) {
/**
* Remove old CSS.
*
* Removes CSS when the textarea is empty, but still retains surrounding styles.
*
* @param string $field_id The CSS option field ID.
* @return bool True on write success, false on failure.
*
* @access public
* @since 2.0
*/
function ot_remove_old_css( $field_id = '' ) {
// Missing $field_id string.
if ( '' === $field_id ) {
return false;
}
// Path to the dynamic.css file.
$filepath = get_stylesheet_directory() . '/dynamic.css';
// Allow filter on path.
$filepath = apply_filters( 'css_option_file_path', $filepath, $field_id );
// Remove CSS from file, but ensure the file is actually CSS first.
if ( is_writeable( $filepath ) && 'css' === end( explode( '.', basename( $filepath ) ) ) ) {
// Open the file.
$f = @fopen( $filepath, 'w' ); // phpcs:ignore
// Can't write to the file return false.
if ( ! $f ) {
/* translators: %s: file path */
$string = esc_html__( 'Unable to open the %s file in write mode.', 'option-tree' );
add_settings_error( 'option-tree', 'dynamic_css', sprintf( $string, '' . $filepath . '
' ), 'error' );
return false;
}
// Get each line in the file.
$markerdata = explode( "\n", implode( '', file( $filepath ) ) );
$searching = true;
// Has array of lines.
if ( ! empty( $markerdata ) ) {
// Foreach line of code.
foreach ( $markerdata as $n => $markerline ) {
// Found beginning of marker, set $searching to false.
if ( "/* BEGIN {$field_id} */" === $markerline ) {
$searching = false;
}
// Searching is true, keep writing each line of CSS.
if ( true === $searching ) {
if ( $n + 1 < count( $markerdata ) ) {
fwrite( $f, "{$markerline}\n" ); // phpcs:ignore
} else {
fwrite( $f, "{$markerline}" ); // phpcs:ignore
}
}
// Found end marker delete old CSS.
if ( "/* END {$field_id} */" === $markerline ) {
fwrite( $f, '' ); // phpcs:ignore
$searching = true;
}
}
}
// Close file.
fclose( $f ); // phpcs:ignore
return true;
}
return false;
}
}
if ( ! function_exists( 'ot_normalize_css' ) ) {
/**
* Normalize CSS
*
* Normalize & Convert all line-endings to UNIX format.
*
* @param string $css The CSS styles.
*
* @return string
*
* @access public
* @since 1.1.8
* @updated 2.0
*/
function ot_normalize_css( $css ) {
// Normalize & Convert.
$css = str_replace( "\r\n", "\n", $css );
$css = str_replace( "\r", "\n", $css );
// Don't allow out-of-control blank lines .
$css = preg_replace( "/\n{2,}/", "\n\n", $css );
return $css;
}
}
if ( ! function_exists( 'ot_loop_through_option_types' ) ) {
/**
* Helper function to loop over the option types.
*
* @param string $type The current option type.
* @param bool $child Whether of not there are children elements.
*
* @return string
*
* @access public
* @since 2.0
*/
function ot_loop_through_option_types( $type = '', $child = false ) {
$content = '';
$types = ot_option_types_array();
if ( $child ) {
unset( $types['list-item'] );
}
foreach ( $types as $key => $value ) {
$content .= '';
}
return $content;
}
}
if ( ! function_exists( 'ot_loop_through_choices' ) ) {
/**
* Helper function to loop over choices.
*
* @param string $name The form element name.
* @param array $choices The array of choices.
*
* @return string
*
* @access public
* @since 2.0
*/
function ot_loop_through_choices( $name, $choices = array() ) {
$content = '';
foreach ( (array) $choices as $key => $choice ) {
if ( is_array( $choice ) ) {
$content .= '' . esc_html__( 'OptionTree->Documentation', 'option-tree' ) . '
' ) . '0,100,1
', '0-100
', '1
' ) . 'value
', 'field_id:is(value)
, field_id:not(value)
, field_id:contains(value)
, field_id:less_than(value)
, field_id:less_than_or_equal_to(value)
, field_id:greater_than(value)
, or field_id:greater_than_or_equal_to(value)
' ) . 'tags. $string = str_replace( array( "\n", '
' ), '', $string );
// Replace
with \r.
$string = str_replace( array( '
', '
', '
' ), "\r", $string );
// Replace
[video]
' ),
'std' => '',
'type' => 'textarea',
),
),
),
$pages
);
}
}
if ( ! function_exists( 'ot_meta_box_post_format_audio' ) ) {
/**
* Returns an array with the post format audio metabox.
*
* @param mixed $pages Excepts a comma separated string or array of
* post_types and is what tells the metabox where to
* display. Default 'post'.
* @return array
*
* @access public
* @since 2.4.0
*/
function ot_meta_box_post_format_audio( $pages = 'post' ) {
if ( ! current_theme_supports( 'post-formats' ) || ! in_array( 'audio', current( get_theme_support( 'post-formats' ) ), true ) ) {
return false;
}
if ( is_string( $pages ) ) {
$pages = explode( ',', $pages );
}
/* translators: %1$s: link to WorPress Codex, %2$s: audio shortcode */
$string = esc_html__( 'Embed audio from services like SoundCloud and Radio. You can find a list of supported oEmbed sites in the %1$s. Alternatively, you could use the built-in %2$s shortcode.', 'option-tree' );
return apply_filters(
'ot_meta_box_post_format_audio',
array(
'id' => 'ot-post-format-audio',
'title' => esc_html__( 'Audio', 'option-tree' ),
'desc' => '',
'pages' => $pages,
'context' => 'side',
'priority' => 'low',
'fields' => array(
array(
'id' => '_format_audio_embed',
'label' => '',
'desc' => sprintf( $string, '' . esc_html__( 'WordPress Codex', 'option-tree' ) . '', '[audio]
' ),
'std' => '',
'type' => 'textarea',
),
),
),
$pages
);
}
}
if ( ! function_exists( 'ot_get_option_type_by_id' ) ) {
/**
* Returns the option type by ID.
*
* @param string $option_id The option ID.
* @param string $settings_id The settings array ID.
* @return string The option type.
*
* @access public
* @since 2.4.2
*/
function ot_get_option_type_by_id( $option_id, $settings_id = '' ) {
if ( empty( $settings_id ) ) {
$settings_id = ot_settings_id();
}
$settings = get_option( $settings_id, array() );
if ( isset( $settings['settings'] ) ) {
foreach ( $settings['settings'] as $value ) {
if ( $option_id === $value['id'] && isset( $value['type'] ) ) {
return $value['type'];
}
}
}
return false;
}
}
if ( ! function_exists( '_ot_settings_potential_shared_terms' ) ) {
/**
* Build an array of potential Theme Options that could share terms.
*
* @return array
*
* @access private
* @since 2.5.4
*/
function _ot_settings_potential_shared_terms() {
$options = array();
$settings = get_option( ot_settings_id(), array() );
$option_types = array(
'category-checkbox',
'category-select',
'tag-checkbox',
'tag-select',
'taxonomy-checkbox',
'taxonomy-select',
);
if ( isset( $settings['settings'] ) ) {
foreach ( $settings['settings'] as $value ) {
if ( isset( $value['type'] ) ) {
if ( 'list-item' === $value['type'] && isset( $value['settings'] ) ) {
$saved = ot_get_option( $value['id'] );
foreach ( $value['settings'] as $item ) {
if ( isset( $value['id'] ) && isset( $item['type'] ) && in_array( $item['type'], $option_types, true ) ) {
$sub_options = array();
foreach ( $saved as $sub_key => $sub_value ) {
if ( isset( $sub_value[ $item['id'] ] ) ) {
$sub_options[ $sub_key ] = $sub_value[ $item['id'] ];
}
}
if ( ! empty( $sub_options ) ) {
$options[] = array(
'id' => $item['id'],
'taxonomy' => $value['taxonomy'],
'parent' => $value['id'],
'value' => $sub_options,
);
}
}
}
}
if ( in_array( $value['type'], $option_types, true ) ) {
$saved = ot_get_option( $value['id'] );
if ( ! empty( $saved ) ) {
$options[] = array(
'id' => $value['id'],
'taxonomy' => $value['taxonomy'],
'value' => $saved,
);
}
}
}
}
}
return $options;
}
}
if ( ! function_exists( '_ot_meta_box_potential_shared_terms' ) ) {
/**
* Build an array of potential Meta Box options that could share terms.
*
* @return array
*
* @access private
* @since 2.5.4
*/
function _ot_meta_box_potential_shared_terms() {
global $ot_meta_boxes;
$options = array();
$settings = $ot_meta_boxes;
$option_types = array(
'category-checkbox',
'category-select',
'tag-checkbox',
'tag-select',
'taxonomy-checkbox',
'taxonomy-select',
);
foreach ( $settings as $setting ) {
if ( isset( $setting['fields'] ) ) {
foreach ( $setting['fields'] as $value ) {
if ( isset( $value['type'] ) ) {
if ( 'list-item' === $value['type'] && isset( $value['settings'] ) ) {
$children = array();
foreach ( $value['settings'] as $item ) {
if ( isset( $value['id'] ) && isset( $item['type'] ) && in_array( $item['type'], $option_types, true ) ) {
$children[ $value['id'] ][] = $item['id'];
}
}
if ( ! empty( $children[ $value['id'] ] ) ) {
$options[] = array(
'id' => $value['id'],
'children' => $children[ $value['id'] ],
'taxonomy' => $value['taxonomy'],
);
}
}
if ( in_array( $value['type'], $option_types, true ) ) {
$options[] = array(
'id' => $value['id'],
'taxonomy' => $value['taxonomy'],
);
}
}
}
}
}
return $options;
}
}
if ( ! function_exists( 'ot_split_shared_term' ) ) {
/**
* Update terms when a term gets split.
*
* @param int $term_id ID of the formerly shared term.
* @param int $new_term_id ID of the new term created for the $term_taxonomy_id.
* @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split.
* @param string $taxonomy Taxonomy for the split term.
*
* @access public
* @since 2.5.4
*/
function ot_split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
unset( $term_taxonomy_id );
// Process the Theme Options.
$settings = _ot_settings_potential_shared_terms();
$old_options = get_option( ot_options_id(), array() );
$new_options = $old_options;
// Process the saved settings.
if ( ! empty( $settings ) && ! empty( $old_options ) ) {
// Loop over the Theme Options.
foreach ( $settings as $option ) {
if ( ! is_array( $option['taxonomy'] ) ) {
$option['taxonomy'] = explode( ',', $option['taxonomy'] );
}
if ( ! in_array( $taxonomy, $option['taxonomy'], true ) ) {
continue;
}
// The option ID was found.
if ( array_key_exists( $option['id'], $old_options ) || ( isset( $option['parent'] ) && array_key_exists( $option['parent'], $old_options ) ) ) {
// This is a list item, we have to go deeper.
if ( isset( $option['parent'] ) ) {
// Loop over the array.
foreach ( $option['value'] as $key => $value ) {
// The value is an array of IDs.
if ( is_array( $value ) ) {
// Loop over the sub array.
foreach ( $value as $sub_key => $sub_value ) {
if ( $sub_value === $term_id ) {
unset( $new_options[ $option['parent'] ][ $key ][ $option['id'] ][ $sub_key ] );
$new_options[ $option['parent'] ][ $key ][ $option['id'] ][ $new_term_id ] = $new_term_id;
}
}
} elseif ( $value === $term_id ) {
unset( $new_options[ $option['parent'] ][ $key ][ $option['id'] ] );
$new_options[ $option['parent'] ][ $key ][ $option['id'] ] = $new_term_id;
}
}
} else {
// The value is an array of IDs.
if ( is_array( $option['value'] ) ) {
// Loop over the array.
foreach ( $option['value'] as $key => $value ) {
// It's a single value, just replace it.
if ( $value === $term_id ) {
unset( $new_options[ $option['id'] ][ $key ] );
$new_options[ $option['id'] ][ $new_term_id ] = $new_term_id;
}
}
// It's a single value, just replace it.
} elseif ( $option['value'] === $term_id ) {
$new_options[ $option['id'] ] = $new_term_id;
}
}
}
}
}
// Options need to be updated.
if ( $old_options !== $new_options ) {
update_option( ot_options_id(), $new_options );
}
// Process the Meta Boxes.
$meta_settings = _ot_meta_box_potential_shared_terms();
if ( ! empty( $meta_settings ) ) {
foreach ( $meta_settings as $option ) {
if ( ! is_array( $option['taxonomy'] ) ) {
$option['taxonomy'] = explode( ',', $option['taxonomy'] );
}
if ( ! in_array( $taxonomy, $option['taxonomy'], true ) ) {
continue;
}
if ( isset( $option['children'] ) ) {
$post_ids = get_posts(
array(
'fields' => 'ids',
'meta_key' => $option['id'], // phpcs:ignore
)
);
if ( $post_ids ) {
foreach ( $post_ids as $post_id ) {
// Get the meta.
$old_meta = get_post_meta( $post_id, $option['id'], true );
$new_meta = $old_meta;
// Has a saved value.
if ( ! empty( $old_meta ) && is_array( $old_meta ) ) {
// Loop over the array.
foreach ( $old_meta as $key => $value ) {
foreach ( $value as $sub_key => $sub_value ) {
if ( in_array( $sub_key, $option['children'], true ) ) {
// The value is an array of IDs.
if ( is_array( $sub_value ) ) {
// Loop over the array.
foreach ( $sub_value as $sub_sub_key => $sub_sub_value ) {
// It's a single value, just replace it.
if ( $sub_sub_value === $term_id ) {
unset( $new_meta[ $key ][ $sub_key ][ $sub_sub_key ] );
$new_meta[ $key ][ $sub_key ][ $new_term_id ] = $new_term_id;
}
}
// It's a single value, just replace it.
} elseif ( $sub_value === $term_id ) {
$new_meta[ $key ][ $sub_key ] = $new_term_id;
}
}
}
}
// Update.
if ( $old_meta !== $new_meta ) {
update_post_meta( $post_id, $option['id'], $new_meta, $old_meta );
}
}
}
}
} else {
$post_ids = get_posts(
array(
'fields' => 'ids',
'meta_query' => array( // phpcs:ignore
'key' => $option['id'],
'value' => $term_id,
'compare' => 'IN',
),
)
);
if ( $post_ids ) {
foreach ( $post_ids as $post_id ) {
// Get the meta.
$old_meta = get_post_meta( $post_id, $option['id'], true );
$new_meta = $old_meta;
// Has a saved value.
if ( ! empty( $old_meta ) ) {
// The value is an array of IDs.
if ( is_array( $old_meta ) ) {
// Loop over the array.
foreach ( $old_meta as $key => $value ) {
// It's a single value, just replace it.
if ( $value === $term_id ) {
unset( $new_meta[ $key ] );
$new_meta[ $new_term_id ] = $new_term_id;
}
}
// It's a single value, just replace it.
} elseif ( $old_meta === $term_id ) {
$new_meta = $new_term_id;
}
// Update.
if ( $old_meta !== $new_meta ) {
update_post_meta( $post_id, $option['id'], $new_meta, $old_meta );
}
}
}
}
}
}
}
}
add_action( 'split_shared_term', 'ot_split_shared_term', 10, 4 );
}