Hotel Raxa - Advanced Booking System Implementation

🏨 Hotel Booking Enhancements:
- Implemented Eagle Booking Advanced Pricing add-on
- Added Booking.com-style rate management system
- Created professional calendar interface for pricing
- Integrated deals and discounts functionality

💰 Advanced Pricing Features:
- Dynamic pricing models (per room, per person, per adult)
- Base rates, adult rates, and child rates management
- Length of stay discounts and early bird deals
- Mobile rates and secret deals implementation
- Seasonal promotions and flash sales

📅 Availability Management:
- Real-time availability tracking
- Stop sell and restriction controls
- Closed to arrival/departure functionality
- Minimum/maximum stay requirements
- Automatic sold-out management

💳 Payment Integration:
- Maintained Redsys payment gateway integration
- Seamless integration with existing Eagle Booking
- No modifications to core Eagle Booking plugin

🛠️ Technical Implementation:
- Custom database tables for advanced pricing
- WordPress hooks and filters integration
- AJAX-powered admin interface
- Data migration from existing Eagle Booking
- Professional calendar view for revenue management

📊 Admin Interface:
- Booking.com-style management dashboard
- Visual rate and availability calendar
- Bulk operations for date ranges
- Statistics and analytics dashboard
- Modal dialogs for quick editing

🔧 Code Quality:
- WordPress coding standards compliance
- Secure database operations with prepared statements
- Proper input validation and sanitization
- Error handling and logging
- Responsive admin interface

🤖 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hotel Raxa Dev
2025-07-11 07:43:22 +02:00
commit 5b1e2453c7
9816 changed files with 2784509 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
<?php
/**
* Redux Framework Admin Notice Class
* Makes instantiating a Redux object an absolute piece of cake.
*
* @package Redux_Framework
* @author Kevin Provance & Dovy Paukstys
* @subpackage Core
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Admin_Notices', false ) ) {
/**
* Redux Admin Notices Class
*
* @since 3.0.0
*/
class Redux_Admin_Notices extends Redux_Class {
/**
* WordPress admin notice array.
*
* @var array
* @access private
*/
private static $notices = array();
/**
* Redux_Admin_Notices constructor.
*
* @param array $redux ReduxFramework object.
* @access public
*/
public function __construct( $redux ) {
parent::__construct( $redux );
add_action( 'wp_ajax_redux_hide_admin_notice', array( $this, 'ajax' ) );
add_action( 'admin_notices', array( $this, 'notices' ), 99 );
add_action( 'admin_init', array( $this, 'dismiss' ), 9 );
}
/**
* Display notices stored in a notice array.
*
* @access public
*/
public function notices() {
$this->admin_notices( self::$notices );
}
/**
* Dismisses admin notice
*
* @access public
*/
public function dismiss() {
$this->dismiss_admin_notice();
}
/**
* Sets an admin notice for display.
*
* @param array $data Notice data.
*/
public static function set_notice( array $data ) {
$type = null;
$msg = null;
$id = null;
$dismiss = null;
// phpcs:ignore WordPress.PHP.DontExtract
extract( $data );
self::$notices[ $parent->args['page_slug'] ][] = array(
'type' => $type,
'msg' => $msg,
'id' => $id . '_' . $parent->args['opt_name'],
'dismiss' => $dismiss,
'color' => $color ?? '#00A2E3',
);
}
/**
* Evaluates a user-dismissed option for displaying admin notices.
*
* @param array $notices Array of stored notices to display.
*
* @return void
* @since 3.2.0
* @access public
*/
public function admin_notices( array $notices = array() ) {
global $current_user;
$core = $this->core();
if ( isset( $_GET['page'] ) && $core->args['page_slug'] === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification
do_action( 'redux_admin_notices_run', $core->args );
// Check for an active admin notice array.
if ( ! empty( $notices ) ) {
if ( isset( $notices[ $core->args['page_slug'] ] ) ) {
// Enum admin notices.
foreach ( $notices[ $core->args['page_slug'] ] as $notice ) {
$add_style = '';
if ( strpos( $notice['type'], 'redux-message' ) !== false ) {
$add_style = 'style="border-left: 4px solid ' . esc_attr( $notice['color'] ) . '!important;"';
}
if ( true === $notice['dismiss'] ) {
// Get user ID.
$userid = $current_user->ID;
if ( ! get_user_meta( $userid, 'ignore_' . $notice['id'] ) ) {
global $wp_version;
$css_id = '';
// Print the notice with the dismiss link.
if ( version_compare( $wp_version, '4.2', '>' ) ) {
$css_id = esc_attr( $notice['id'] );
$css_class = esc_attr( $notice['type'] ) . ' redux-notice notice is-dismissible redux-notice';
$nonce = wp_create_nonce( $notice['id'] . $userid . 'nonce' );
echo '<div ' . $add_style . ' id="' . esc_attr( $css_id ) . '" class="' . esc_attr( $css_class ) . '">'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<input type="hidden" class="dismiss_data" id="' . esc_attr( $css_id ) . '" value="' . esc_attr( $nonce ) . '">';
echo '<p>' . wp_kses_post( $notice['msg'] ) . '</p>';
echo '</div>';
} else {
echo '<div ' . esc_html( $add_style ) . ' class="' . esc_attr( $notice['type'] ) . ' notice is-dismissable"><p>' . wp_kses_post( $notice['msg'] ) . '&nbsp;&nbsp;<a href="?dismiss=true&amp;id=' . esc_attr( $css_id ) . '">' . esc_html__( 'Dismiss', 'redux-framework' ) . '</a>.</p></div>';
}
}
} else {
// Standard notice.
echo '<div ' . esc_html( $add_style ) . ' class="' . esc_attr( $notice['type'] ) . ' notice"><p>' . wp_kses_post( $notice['msg'] ) . '</a>.</p></div>';
}
?>
<script>
jQuery( document ).ready( function( $ ) {
$( document.body ).on(
'click', '.redux-notice.is-dismissible .notice-dismiss', function( e ) {
e.preventDefault();
var $data = $( this ).parent().find( '.dismiss_data' );
$.post(
ajaxurl, {
action: 'redux_hide_admin_notice',
id: $data.attr( 'id' ),
nonce: $data.val()
}
);
} );
} );
</script>
<?php
}
}
}
// Clear the admin notice array.
self::$notices[ $core->args['opt_name'] ] = array();
}
}
/**
* Updates user meta to store dismiss notice preference.
*
* @since 3.2.0
* @access private
* @return void
*/
private function dismiss_admin_notice() {
global $current_user;
// Verify the dismissed notice and id parameters are present.
if ( isset( $_GET['dismiss'] ) && isset( $_GET['id'] ) ) {
if ( isset( $_GET['nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['nonce'] ) ), 'redux_hint_toggle' ) ) {
if ( 'true' === $_GET['dismiss'] || 'false' === $_GET['dismiss'] ) {
// Get the user id.
$userid = $current_user->ID;
// Get the notice id.
$id = sanitize_text_field( wp_unslash( $_GET['id'] ) );
$val = sanitize_text_field( wp_unslash( $_GET['dismiss'] ) );
// Add the dismissed request to the user meta.
update_user_meta( $userid, 'ignore_' . $id, $val );
}
} else {
wp_nonce_ays( 'redux_hint_toggle' );
}
}
}
/**
* Updates user meta to store dismiss notice preference
*
* @since 3.2.0
* @access public
* @return void
*/
public function ajax() {
global $current_user;
if ( isset( $_POST['id'] ) ) {
// Get the notice id.
$id = explode( '&', sanitize_text_field( wp_unslash( $_POST['id'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
$id = $id[0];
// Get the user id.
$userid = $current_user->ID;
if ( ! isset( $_POST['nonce'] ) || ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), $id . $userid . 'nonce' ) ) ) {
die( 0 );
} else {
// Add the dismissed request to the user meta.
update_user_meta( $userid, 'ignore_' . $id, true );
}
}
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* Redux AJAX Save Class
*
* @class Redux_Core
* @version 4.0.0
* @package Redux Framework/Classes
* @noinspection PhpConditionCheckedByNextConditionInspection
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_AJAX_Save', false ) ) {
/**
* Class Redux_AJAX_Save
*/
class Redux_AJAX_Save extends Redux_Class {
/**
* Redux_AJAX_Save constructor.
* array_merge_recursive_distinct
*
* @param object $redux ReduxFramework object.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
add_action( 'wp_ajax_' . $this->args['opt_name'] . '_ajax_save', array( $this, 'save' ) );
}
/**
* AJAX callback to save the option panel values.
*
* @throws ReflectionException Exception.
*/
public function save() {
$redux = null;
$core = $this->core();
if ( ! isset( $_REQUEST['nonce'] ) || ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'redux_ajax_nonce' . $this->args['opt_name'] ) ) ) {
echo wp_json_encode(
array(
'status' => esc_html__( 'Invalid security credential. Please reload the page and try again.', 'redux-framework' ),
'action' => '',
)
);
die();
}
if ( ! Redux_Helpers::current_user_can( $core->args['page_permissions'] ) ) {
echo wp_json_encode(
array(
'status' => esc_html__( 'Invalid user capability. Please reload the page and try again.', 'redux-framework' ),
'action' => '',
)
);
die();
}
if ( isset( $_POST['opt_name'] ) && ! empty( $_POST['opt_name'] ) && isset( $_POST['data'] ) && ! empty( $_POST['data'] ) ) {
$redux = Redux::instance( sanitize_text_field( wp_unslash( $_POST['opt_name'] ) ) );
if ( ! empty( $redux->args['opt_name'] ) ) {
$post_data = wp_unslash( $_POST['data'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
// New method to avoid input_var nonsense. Thanks, @harunbasic.
$values = Redux_Functions_Ex::parse_str( $post_data );
$values = $values[ $redux->args['opt_name'] ];
if ( ! empty( $values ) ) {
try {
if ( isset( $redux->validation_ran ) ) {
unset( $redux->validation_ran );
}
$redux->options_class->set( $redux->options_class->validate_options( $values ) );
$do_reload = false;
if ( isset( $core->required_class->reload_fields ) && ! empty( $core->required_class->reload_fields ) ) {
if ( ! empty( $core->transients['changed_values'] ) ) {
foreach ( $core->required_class->reload_fields as $val ) {
if ( array_key_exists( $val, $core->transients['changed_values'] ) ) {
$do_reload = true;
}
}
}
}
if ( $do_reload || ( isset( $values['defaults'] ) && ! empty( $values['defaults'] ) ) || ( isset( $values['defaults-section'] ) && ! empty( $values['defaults-section'] ) ) || ( isset( $values['import_code'] ) && ! empty( $values['import_code'] ) ) || ( isset( $values['import_link'] ) && ! empty( $values['import_link'] ) ) ) {
echo wp_json_encode(
array(
'status' => 'success',
'action' => 'reload',
)
);
die();
}
$redux->enqueue_class->get_warnings_and_errors_array();
$return_array = array(
'status' => 'success',
'options' => $redux->options,
'errors' => $redux->enqueue_class->localize_data['errors'] ?? null,
'warnings' => $redux->enqueue_class->localize_data['warnings'] ?? null,
'sanitize' => $redux->enqueue_class->localize_data['sanitize'] ?? null,
);
} catch ( Exception $e ) {
$return_array = array( 'status' => $e->getMessage() );
}
} else {
echo wp_json_encode(
array(
'status' => esc_html__( 'Your panel has no fields. Nothing to save.', 'redux-framework' ),
)
);
die();
}
}
}
if ( isset( $core->transients['run_compiler'] ) && $core->transients['run_compiler'] ) {
$core->no_output = true;
$temp = $core->args['output_variables_prefix'];
// Allow the override of variable's prefix for use by SCSS or LESS.
if ( isset( $core->args['compiler_output_variables_prefix'] ) ) {
$core->args['output_variables_prefix'] = $core->args['compiler_output_variables_prefix'];
}
$core->output_class->enqueue();
$core->args['output_variables_prefix'] = $temp;
try {
// phpcs:ignore WordPress.NamingConventions.ValidVariableName
$compiler_css = $core->compilerCSS; // Backward compatibility variable.
/**
* Action 'redux/options/{opt_name}/compiler'
*
* @param array $options Global options.
* @param string $css CSS that get sent to the compiler hook.
* @param array $changed_values Changed option values.
* @param array $output_variables Output variables.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/options/' . $core->args['opt_name'] . '/compiler', $core->options, $compiler_css, $core->transients['changed_values'], $core->output_variables );
/**
* Action 'redux/options/{opt_name}/compiler/advanced'
*
* @param object $redux ReduxFramework object.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/options/' . $core->args['opt_name'] . '/compiler/advanced', $core );
} catch ( Exception $e ) {
$return_array = array( 'status' => $e->getMessage() );
}
unset( $core->transients['run_compiler'] );
$core->transient_class->set();
}
if ( isset( $return_array ) ) {
if ( 'success' === $return_array['status'] ) {
$panel = new Redux_Panel( $redux );
ob_start();
$panel->notification_bar();
$notification_bar = ob_get_contents();
ob_end_clean();
$return_array['notification_bar'] = $notification_bar;
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo wp_json_encode( apply_filters( 'redux/options/' . $core->args['opt_name'] . '/ajax_save/response', $return_array ) );
}
die();
}
}
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* Redux Select2 AJAX Class
*
* @class Redux_AJAX_Select2
* @version 4.0.0
* @package Redux Framework/Classes
* @noinspection PhpConditionCheckedByNextConditionInspection
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_AJAX_Select2', false ) ) {
/**
* Class Redux_AJAX_Select2
*/
class Redux_AJAX_Select2 extends Redux_Class {
/**
* Redux_AJAX_Select2 constructor.
*
* @param object $redux ReduxFramework object pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
add_action( "wp_ajax_redux_{$redux->args['opt_name']}_select2", array( $this, 'ajax' ) );
}
/**
* AJAX callback for select2 match search.
*/
public function ajax() {
$core = $this->core();
if ( isset( $_REQUEST['nonce'] ) && isset( $_REQUEST['action'] ) ) {
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) ) ) {
wp_send_json_error( esc_html__( 'Invalid security credential. Please reload the page and try again.', 'redux-framework' ) );
}
if ( ! Redux_Helpers::current_user_can( $this->parent->args['page_permissions'] ) ) {
wp_send_json_error( esc_html__( 'Invalid user capability. Please reload the page and try again.', 'redux-framework' ) );
}
if ( isset( $_REQUEST['data'] ) ) {
$args = isset( $_REQUEST['data_args'] ) ? json_decode( sanitize_text_field( wp_unslash( $_REQUEST['data_args'] ) ), true ) : array();
$args = wp_parse_args(
$args,
array(
's' => isset( $_REQUEST['q'] ) && ! empty( $_REQUEST['q'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['q'] ) ) : '',
)
);
if ( isset( $_REQUEST['q'] ) && ! empty( $_REQUEST['q'] ) ) {
$criteria = sanitize_text_field( wp_unslash( $_REQUEST['q'] ) );
$args['s'] = $criteria;
}
$return = $core->wordpress_data->get( sanitize_text_field( wp_unslash( $_REQUEST['data'] ) ), $args );
if ( is_array( $return ) && ! empty( $_REQUEST['action'] ) ) {
if ( ! empty( $args['s'] ) ) {
$keys = array_keys( $return );
$values = array_values( $return );
$to_json = array();
// Search all the values.
$search_values = preg_grep( '~' . $args['s'] . '~i', $values );
if ( ! empty( $search_values ) ) {
foreach ( $search_values as $id => $val ) {
$to_json[ $keys[ $id ] ] = array(
'id' => $keys[ $id ],
'text' => $val,
);
}
}
// Search all the keys.
$search_keys = preg_grep( '~' . $args['s'] . '~i', $keys );
if ( ! empty( $search_keys ) ) {
foreach ( $search_keys as $id => $val ) {
$to_json[ $val ] = array(
'id' => $val,
'text' => $values[ $id ],
);
}
}
wp_send_json_success( array_values( $to_json ) );
}
}
}
}
}
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* Redux Typography AJAX Class
*
* @class Redux_Core
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_AJAX_Typography', false ) ) {
/**
* Class Redux_AJAX_Typography
*/
class Redux_AJAX_Typography extends Redux_Class {
/**
* Redux_AJAX_Typography constructor.
*
* @param object $redux ReduxFramework object.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
add_action( 'wp_ajax_redux_update_google_fonts', array( $this, 'google_fonts_update' ) );
}
/**
* Google font AJAX callback
*
* @return void
*/
public function google_fonts_update() {
$field_class = 'Redux_typography';
if ( ! class_exists( $field_class ) ) {
$dir = str_replace( '/classes', '', Redux_Functions_Ex::wp_normalize_path( __DIR__ ) );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$class_file = apply_filters( 'redux-typeclass-load', $dir . '/fields/typography/class-redux-typography.php', $field_class );
if ( $class_file ) {
require_once $class_file;
}
}
if ( class_exists( $field_class ) && method_exists( $field_class, 'google_fonts_update_ajax' ) ) {
$f = new $field_class( array(), '', $this->parent );
$f->google_fonts_update_ajax();
}
die();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,401 @@
<?php
/**
* Redux Framework Args Class
*
* @package Redux_Framework/Classes
* @noinspection PhpConditionCheckedByNextConditionInspection
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Args', false ) ) {
/**
* Class Redux_Args
*/
class Redux_Args {
/**
* Returns entire arguments array.
*
* @var array|mixed
*/
public $get = array();
/**
* ReduxFramework object.
*
* @var null
*/
private $parent;
/**
* Switch to omit social icons if dev_mode is set to true and Redux defaults are used.
*
* @var bool
*/
public $omit_icons = false;
/**
* Switch to omit support menu items if dev_mode is set to true and redux defaults are used.
*
* @var bool
*/
public $omit_items = false;
/**
* Flag to force dev_mod to true if in localhost or WP_DEBUG is set to true.
*
* @var bool
*/
public $dev_mode_forced = false;
/**
* Redux_Args constructor.
*
* @param object $redux ReduxFramework object.
* @param array $args Global arguments array.
*/
public function __construct( $redux, array $args ) {
$this->parent = $redux;
$default = array(
'opt_name' => '',
'last_tab' => '',
'menu_icon' => '',
'menu_title' => '',
'page_title' => '',
'page_slug' => '',
'page_permissions' => 'manage_options',
'menu_type' => 'menu',
'page_parent' => 'themes.php',
'page_priority' => null,
'allow_sub_menu' => true,
'save_defaults' => true,
'footer_credit' => '',
'async_typography' => false,
'disable_google_fonts_link' => false,
'class' => '',
'admin_bar' => true,
'admin_bar_priority' => 999,
'admin_bar_icon' => '',
'help_tabs' => array(),
'help_sidebar' => '',
'database' => '',
'customizer' => false,
'global_variable' => '',
'output' => true,
'output_variables_prefix' => '--',
'compiler_output_variables_prefix' => '$',
'compiler' => true,
'output_tag' => true,
'output_location' => array( 'frontend' ),
'transient_time' => '',
'default_show' => false,
'default_mark' => '',
'disable_save_warn' => false,
'open_expanded' => false,
'hide_expand' => false,
'network_admin' => false,
'network_sites' => true,
'hide_reset' => false,
'hide_save' => false,
'hints' => array(
'icon' => 'el el-question-sign',
'icon_position' => 'right',
'icon_color' => 'lightgray',
'icon_size' => 'normal',
'tip_style' => array(
'color' => 'light',
'shadow' => true,
'rounded' => false,
'style' => '',
),
'tip_position' => array(
'my' => 'top_left',
'at' => 'bottom_right',
),
'tip_effect' => array(
'show' => array(
'effect' => 'slide',
'duration' => '500',
'event' => 'mouseover',
),
'hide' => array(
'effect' => 'fade',
'duration' => '500',
'event' => 'click mouseleave',
),
),
),
'font_weights' => array(
array(
'id' => '400',
'name' => __( 'Regular 400', 'redux-framework' ),
),
array(
'id' => '400italic',
'name' => __( 'Regular 400 Italic', 'redux-framework' ),
),
array(
'id' => '700',
'name' => __( 'Bold 700', 'redux-framework' ),
),
array(
'id' => '700italic',
'name' => __( 'Bold 700 Italic', 'redux-framework' ),
),
),
'show_import_export' => true,
'show_options_object' => true,
'dev_mode' => true,
'templates_path' => '',
'ajax_save' => true,
'use_cdn' => true,
'cdn_check_time' => 1440,
'options_api' => true,
'allow_tracking' => true,
'admin_theme' => 'wp',
'elusive_frontend' => false,
'fontawesome_frontend' => false,
'flyout_submenus' => true,
'font_display' => 'swap', // block|swap|fallback|optional.
'load_on_cron' => false,
'search' => false,
);
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$default = apply_filters( 'redux/pro/args/defaults', $default );
$args = Redux_Functions::parse_args( $args, $default );
$args = $this->args( $args );
$args = $this->default_cleanup( $args );
if ( ! in_array( $args['font_display'], array( 'block', 'swap', 'fallback', 'optional' ), true ) ) {
$args['font_display'] = 'swap';
}
if ( isset( $args['async_typography'] ) && $args['async_typography'] ) {
$args['async_typography'] = false;
}
$this->get = $args;
$this->parent->args = $args;
if ( 'redux_extensions_demo' !== $args['opt_name'] && 'redux_demo' !== $args['opt_name'] ) {
$this->change_demo_defaults( $args );
}
}
/**
* Builds and sanitizes a global args array.
*
* @param array $args Global args.
*
* @return array
*/
private function args( array $args ): array {
$args = $this->no_errors_please( $args );
$this->parent->old_opt_name = $args['opt_name'];
$args = $this->filters( $args );
if ( ! function_exists( 'wp_rand' ) ) {
require_once ABSPATH . '/wp-includes/pluggable.php';
}
if ( $args['opt_name'] === $this->parent->old_opt_name ) {
$this->parent->old_opt_name = null;
unset( $this->parent->old_opt_name );
}
// Do not save the defaults if we're on a live preview!
if ( 'customize' === $GLOBALS['pagenow'] && isset( $_GET['customize_theme'] ) && ! empty( $_GET['customize_theme'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$args['save_defaults'] = false;
}
return $this->shim( $args );
}
/**
* Apply filters to arg data.
*
* @param array $args Global args.
*
* @return mixed|void
*/
private function filters( array $args ) {
/**
* Filter 'redux/args/{opt_name}'
*
* @param array $args ReduxFramework configuration
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$args = apply_filters( "redux/args/{$args['opt_name']}", $args );
/**
* Filter 'redux/options/{opt_name}/args'
*
* @param array $args ReduxFramework configuration
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
return apply_filters( "redux/options/{$args['opt_name']}/args", $args );
}
/**
* Sanitize args that should not be empty.
*
* @param array $args Global args.
*
* @return array
*/
private function no_errors_please( array $args ): array {
if ( empty( $args['transient_time'] ) ) {
$args['transient_time'] = 60 * MINUTE_IN_SECONDS;
}
if ( empty( $args['footer_credit'] ) ) {
$footer_text = sprintf(
/* translators: 1: Redux, 2: Link to plugin review */
__( 'Enjoyed %1$s? Please leave us a %2$s rating. We really appreciate your support!', 'redux-framework' ),
'<strong>' . __( 'Redux', 'redux-framework' ) . '</strong>',
'<a href="https://wordpress.org/support/plugin/redux-framework/reviews/?filter=5/#new-post" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
);
$args['footer_credit'] = '<span id="footer-thankyou">' . $footer_text . '</span>';
}
if ( empty( $args['menu_title'] ) ) {
$args['menu_title'] = esc_html__( 'Options', 'redux-framework' );
}
if ( empty( $args['page_title'] ) ) {
$args['page_title'] = esc_html__( 'Options', 'redux-framework' );
}
// Auto creates the page_slug appropriately.
if ( empty( $args['page_slug'] ) ) {
if ( ! empty( $args['display_name'] ) ) {
$args['page_slug'] = sanitize_html_class( $args['display_name'] );
} elseif ( ! empty( $args['page_title'] ) ) {
$args['page_slug'] = sanitize_html_class( $args['page_title'] );
} elseif ( ! empty( $args['menu_title'] ) ) {
$args['page_slug'] = sanitize_html_class( $args['menu_title'] );
} else {
$args['page_slug'] = str_replace( '-', '_', $args['opt_name'] );
}
}
return $args;
}
/**
* Shims for much older v3 configs.
*
* @param array $args Global args.
*
* @return array
*/
private function shim( array $args ): array {
/**
* SHIM SECTION
* Old variables and ways of doing things that need correcting. ;)
* */
// Variable name change.
if ( ! empty( $args['page_cap'] ) ) {
$args['page_permissions'] = $args['page_cap'];
unset( $args['page_cap'] );
}
if ( ! empty( $args['page_position'] ) ) {
$args['page_priority'] = $args['page_position'];
unset( $args['page_position'] );
}
if ( ! empty( $args['page_type'] ) ) {
$args['menu_type'] = $args['page_type'];
unset( $args['page_type'] );
}
return $args;
}
/**
* Verify to see if dev has bothered to change admin bar links and share icons from demo data to their own.
*
* @param array $args Global args.
*/
private function change_demo_defaults( array $args ) {
if ( $args['dev_mode'] || true === Redux_Helpers::is_local_host() ) {
if ( ! empty( $args['admin_bar_links'] ) ) {
foreach ( $args['admin_bar_links'] as $arr ) {
if ( is_array( $arr ) && ! empty( $arr ) ) {
foreach ( $arr as $y ) {
if ( strpos( Redux_Core::strtolower( $y ), 'redux' ) !== false ) {
$this->omit_items = true;
break;
}
}
}
}
}
if ( ! empty( $args['share_icons'] ) ) {
foreach ( $args['share_icons'] as $arr ) {
if ( is_array( $arr ) && ! empty( $arr ) ) {
foreach ( $arr as $y ) {
if ( strpos( Redux_Core::strtolower( $y ), 'redux' ) !== false ) {
$this->omit_icons = true;
}
}
}
}
}
}
}
/**
* Fix other arg criteria that sometimes gets hosed up.
*
* @param array $args Global args.
*
* @return array
* @noinspection PhpStrictComparisonWithOperandsOfDifferentTypesInspection
*/
private function default_cleanup( array $args ): array {
// Fix the global variable name.
if ( '' === $args['global_variable'] && false !== $args['global_variable'] ) {
$args['global_variable'] = str_replace( '-', '_', $args['opt_name'] );
}
if ( isset( $args['customizer_only'] ) && $args['customizer_only'] ) {
$args['menu_type'] = 'hidden';
$args['customizer'] = true;
$args['admin_bar'] = false;
$args['allow_sub_menu'] = false;
}
// Check if the Airplane Mode plugin is installed.
if ( class_exists( 'Airplane_Mode_Core' ) ) {
$airplane = Airplane_Mode_Core::getInstance();
if ( method_exists( $airplane, 'enabled' ) ) {
if ( $airplane->enabled() ) {
$args['use_cdn'] = false;
}
} elseif ( 'on' === $airplane->check_status() ) {
$args['use_cdn'] = false;
}
}
return $args;
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* Register an autoloader for custom mu-plugins.
*
* @package redux-framework
*/
/**
* Class Autoloader
*
* @package altis/core
*/
class Redux_Autoloader {
const NS_SEPARATOR = '\\';
/**
* Prefix to validate against.
*
* @var string
*/
protected $prefix;
/**
* String length of the prefix.
*
* @var int
*/
protected $prefix_length;
/**
* Path to validate.
*
* @var string
*/
protected $path;
/**
* Autoloader constructor.
*
* @param string $prefix Prefix to validate against.
* @param string $path Path to validate.
*/
public function __construct( string $prefix, string $path ) {
$this->prefix = $prefix;
$this->prefix_length = strlen( $prefix );
$this->path = trailingslashit( $path );
}
/**
* Load a class file if it matches our criteria.
*
* @param string $classname Class to test and/or load.
*/
public function load( string $classname ) {
if ( strpos( $classname, 'Redux' ) === false ) {
return;
}
// Strip prefix from the start (ala PSR-4).
$classname = substr( $classname, $this->prefix_length + 1 );
if ( function_exists( 'mb_strtolower' ) && function_exists( 'mb_detect_encoding' ) ) {
$classname = mb_strtolower( $classname, mb_detect_encoding( $classname ) );
} else {
$classname = strtolower( $classname );
}
$file = '';
// Split on namespace separator.
$last_ns_pos = strripos( $classname, self::NS_SEPARATOR );
if ( false !== $last_ns_pos ) {
$namespace = substr( $classname, 0, $last_ns_pos );
$classname = substr( $classname, $last_ns_pos + 1 );
$file = str_replace( self::NS_SEPARATOR, DIRECTORY_SEPARATOR, $namespace ) . DIRECTORY_SEPARATOR;
}
$file_prefix = $file;
$file = $file_prefix . 'class-' . str_replace( '_', '-', $classname ) . '.php';
$path = $this->path . $file;
if ( file_exists( $path ) ) {
require_once $path;
} else {
$file = $file_prefix . 'class-redux-' . str_replace( '_', '-', $classname ) . '.php';
$path = $this->path . $file;
if ( file_exists( $path ) ) {
require_once $path;
}
}
}
}

View File

@@ -0,0 +1,275 @@
<?php
/**
* Redux Framework CDN Container Class
*
* @author Kevin Provance (kprovance)
* @package Redux_Framework/Classes
* @noinspection PhpIgnoredClassAliasDeclaration
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_CDN', false ) ) {
/**
* Class Redux_CDN
*/
class Redux_CDN {
/**
* Pointer to ReduxFramework object.
*
* @var object
*/
public static $parent;
/**
* Flag to check for set status.
*
* @var bool
*/
private static $set;
/**
* Check for enqueued status of style/script.
*
* @param string $handle File handle.
* @param string $mode Mode to check.
* @param bool $is_script Flag for scrip/style.
*
* @return bool
* @noinspection PhpSameParameterValueInspection
*/
private static function is_enqueued( string $handle, string $mode = 'enqueued', bool $is_script = true ): bool {
if ( $is_script ) {
return wp_script_is( $handle, $mode );
} else {
return wp_style_is( $handle, $mode );
}
}
/**
* Register script/style.
*
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param mixed $footer_or_media True or 'all'.
* @param bool $is_script Script or style.
*/
private static function register( string $handle, string $src_cdn, array $deps, string $ver, $footer_or_media, bool $is_script = true ) {
if ( $is_script ) {
wp_register_script( $handle, $src_cdn, $deps, $ver, $footer_or_media );
} else {
wp_register_style( $handle, $src_cdn, $deps, $ver, $footer_or_media );
}
}
/**
* Enqueue script or style.
*
* @param string $handle File handle.
* @param string|null $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param mixed $footer_or_media True or 'all'.
* @param bool $is_script Script or style.
*/
private static function enqueue( string $handle, ?string $src_cdn, array $deps, string $ver, $footer_or_media, bool $is_script = true ) {
if ( $is_script ) {
wp_enqueue_script( $handle, $src_cdn, $deps, $ver, $footer_or_media );
} else {
wp_enqueue_style( $handle, $src_cdn, $deps, $ver, $footer_or_media );
}
}
/**
* Enqueue/Register CDN
*
* @param bool $register Register or enqueue.
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param mixed $footer_or_media True or 'all'.
* @param bool $is_script Script or style.
*/
private static function cdn( bool $register, string $handle, string $src_cdn, array $deps, string $ver, $footer_or_media, bool $is_script ) {
$tran_key = '_style_cdn_is_up';
if ( $is_script ) {
$tran_key = '_script_cdn_is_up';
}
$cdn_is_up = get_transient( $handle . $tran_key );
if ( $cdn_is_up ) {
if ( $register ) {
self::register( $handle, $src_cdn, $deps, $ver, $footer_or_media, $is_script );
} else {
self::enqueue( $handle, $src_cdn, $deps, $ver, $footer_or_media, $is_script );
}
} else {
$prefix = '/' === $src_cdn[1] ? 'http:' : '';
// phpcs:ignore WordPress.PHP.NoSilencedErrors
$cdn_response = @wp_remote_get( $prefix . $src_cdn );
if ( is_wp_error( $cdn_response ) || 200 !== wp_remote_retrieve_response_code( $cdn_response ) ) {
if ( class_exists( 'Redux_Vendor_URL' ) || class_exists( 'Redux_VendorURL' ) ) {
if ( class_exists( 'Redux_Vendor_URL' ) ) {
$src = Redux_Vendor_URL::get_url( $handle );
} else {
$src = Redux_VendorURL::get_url( $handle );
}
if ( $register ) {
self::register( $handle, $src, $deps, $ver, $footer_or_media, $is_script );
} else {
self::enqueue( $handle, $src, $deps, $ver, $footer_or_media, $is_script );
}
} elseif ( ! self::is_enqueued( $handle, 'enqueued', $is_script ) ) {
$msg = esc_html__( 'Please wait a few minutes, then try refreshing the page. Unable to load some remotely hosted scripts.', 'redux-framework' );
if ( self::$parent->args['dev_mode'] ) {
// translators: %s: URL.
$msg = sprintf( esc_html__( 'If you are developing offline, please download and install the %s plugin/extension to bypass our CDN and avoid this warning', 'redux-framework' ), '<a href="https://github.com/reduxframework/redux-vendor-support" target="_blank">Redux Vendor Support</a>' );
}
// translators: %s: CDN handle.
$msg = '<strong>' . esc_html__( 'Redux Framework Warning', 'redux-framework' ) . '</strong><br/>' . sprintf( esc_html__( '%s CDN unavailable. Some controls may not render properly.', 'redux-framework' ), $handle ) . ' ' . $msg;
$data = array(
'parent' => self::$parent,
'type' => 'error',
'msg' => $msg,
'id' => $handle . $tran_key,
'dismiss' => false,
);
Redux_Admin_Notices::set_notice( $data );
}
} else {
set_transient( $handle . $tran_key, true, MINUTE_IN_SECONDS * self::$parent->args['cdn_check_time'] );
if ( $register ) {
self::register( $handle, $src_cdn, $deps, $ver, $footer_or_media, $is_script );
} else {
self::enqueue( $handle, $src_cdn, $deps, $ver, $footer_or_media, $is_script );
}
}
}
}
/**
* Register/enqueue file from vendor library.
*
* @param bool $register Register or enqueue.
* @param string $handle File handle.
* @param array $deps File deps.
* @param string $ver File version.
* @param mixed $footer_or_media True or 'all'.
* @param bool $is_script Script or style.
*/
private static function vendor_plugin( bool $register, string $handle, array $deps, string $ver, $footer_or_media, bool $is_script ) {
if ( class_exists( 'Redux_Vendor_URL' ) || class_exists( 'Redux_VendorURL' ) ) {
if ( class_exists( 'Redux_Vendor_URL' ) ) {
$src = Redux_Vendor_URL::get_url( $handle );
} else {
$src = Redux_VendorURL::get_url( $handle );
}
if ( $register ) {
self::register( $handle, $src, $deps, $ver, $footer_or_media, $is_script );
} else {
self::enqueue( $handle, $src, $deps, $ver, $footer_or_media, $is_script );
}
} elseif ( ! self::$set ) {
// translators: %s: Vendor support URL. %s: Admin plugins page.
$msg = sprintf( esc_html__( 'The %1$s (or extension) is either not installed or not activated and thus, some controls may not render properly. Please ensure that it is installed and %2$s', 'redux-framework' ), '<a href="https://github.com/reduxframework/redux-vendor-support">Vendor Support plugin</a>', '<a href="' . admin_url( 'plugins.php' ) . '">' . esc_html__( 'activated.', 'redux-framework' ) . '</a>' );
$data = array(
'parent' => self::$parent,
'type' => 'error',
'msg' => $msg,
'id' => $handle,
'dismiss' => false,
);
Redux_Admin_Notices::set_notice( $data );
self::$set = true;
}
}
/**
* Register style CDN or local.
*
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param string $media True or 'all'.
*/
public static function register_style( string $handle, string $src_cdn, array $deps = array(), string $ver = '', string $media = 'all' ) {
if ( empty( self::$parent ) || self::$parent->args['use_cdn'] ) {
self::cdn( true, $handle, $src_cdn, $deps, $ver, $media, false );
} else {
self::vendor_plugin( true, $handle, $deps, $ver, $media, false );
}
}
/** Register script CDN or local.
*
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param bool $in_footer Script in footer.
*/
public static function register_script( string $handle, string $src_cdn, array $deps = array(), string $ver = '', bool $in_footer = false ) {
if ( empty( self::$parent ) || self::$parent->args['use_cdn'] ) {
self::cdn( true, $handle, $src_cdn, $deps, $ver, $in_footer, true );
} else {
self::vendor_plugin( true, $handle, $deps, $ver, $in_footer, true );
}
}
/**
* Enqueue style CDN or local.
*
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File deps.
* @param string $ver File version.
* @param string $media Media type.
*/
public static function enqueue_style( string $handle, string $src_cdn, array $deps = array(), string $ver = '', string $media = 'all' ) {
if ( self::$parent->args['use_cdn'] ) {
self::cdn( false, $handle, $src_cdn, $deps, $ver, $media, false );
} else {
self::vendor_plugin( false, $handle, $deps, $ver, $media, false );
}
}
/**
* Enqueue script CDN or local.
*
* @param string $handle File handle.
* @param string $src_cdn CDN source.
* @param array $deps File seps.
* @param string $ver File version.
* @param bool $in_footer Script in footer.
*/
public static function enqueue_script( string $handle, string $src_cdn, array $deps = array(), string $ver = '', bool $in_footer = false ) {
if ( self::$parent->args['use_cdn'] ) {
self::cdn( false, $handle, $src_cdn, $deps, $ver, $in_footer, true );
} else {
self::vendor_plugin( false, $handle, $deps, $ver, $in_footer, true );
}
}
}
}
if ( ! class_exists( 'Redux_Vendor_URL' ) && class_exists( 'Redux_Extension_Vendor_Support' ) ) {
class_alias( 'Redux_VendorURL', 'Redux_Vendor_URL' );
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* Redux Class
*
* @class Redux_Class
* @version 4.0.0
* @package Redux Framework/Classes
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Class', false ) ) {
/**
* Class Redux_Class
*/
class Redux_Class {
/**
* Pointer to ReduxFramework object.
*
* @var null|ReduxFramework
*/
public $parent = null;
/**
* Global arguments array.
*
* @var array|mixed|void
*/
public $args = array();
/**
* Project opt_name
*
* @var mixed|string
*/
public $opt_name = '';
/**
* Redux_Class constructor.
*
* @param null|object $redux Pointer to ReduxFramework object.
*/
public function __construct( $redux = null ) {
if ( is_object( $redux ) ) {
$this->parent = $redux;
$this->args = $redux->args;
$this->opt_name = $this->args['opt_name'];
}
}
/**
* Pointer to a project-specific ReduxFramework object.
*
* @return null|object|ReduxFramework
*/
public function core() {
if ( isset( $this->opt_name ) && '' !== $this->opt_name ) {
return Redux::instance( $this->opt_name );
}
return null;
}
}
}

View File

@@ -0,0 +1,334 @@
<?php
/**
* Redux Color Manipulator Class
*
* @class Redux_Core
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Colors', false ) ) {
/**
* Class Redux_Colors
*/
class Redux_Colors extends Redux_Class {
/**
* Sanitizes a HEX value.
* The way this works is by splitting the string in 6 substrings.
* Each sub-string is individually sanitized, and the result is then returned.
*
* @param string $color The hex value of a color.
* @param boolean $hash Whether we want to include a hash (#) at the beginning or not.
*
* @return string The sanitized hex color.
*/
public static function sanitize_hex( string $color = '#FFFFFF', bool $hash = true ): string {
$word_colors = array(
'aliceblue' => 'F0F8FF',
'antiquewhite' => 'FAEBD7',
'aqua' => '00FFFF',
'aquamarine' => '7FFFD4',
'azure' => 'F0FFFF',
'beige' => 'F5F5DC',
'bisque' => 'FFE4C4',
'black' => '000000',
'blanchedalmond' => 'FFEBCD',
'blue' => '0000FF',
'blueviolet' => '8A2BE2',
'brown' => 'A52A2A',
'burlywood' => 'DEB887',
'cadetblue' => '5F9EA0',
'chartreuse' => '7FFF00',
'chocolate' => 'D2691E',
'coral' => 'FF7F50',
'cornflowerblue' => '6495ED',
'cornsilk' => 'FFF8DC',
'crimson' => 'DC143C',
'cyan' => '00FFFF',
'darkblue' => '00008B',
'darkcyan' => '008B8B',
'darkgoldenrod' => 'B8860B',
'darkgray' => 'A9A9A9',
'darkgreen' => '006400',
'darkgrey' => 'A9A9A9',
'darkkhaki' => 'BDB76B',
'darkmagenta' => '8B008B',
'darkolivegreen' => '556B2F',
'darkorange' => 'FF8C00',
'darkorchid' => '9932CC',
'darkred' => '8B0000',
'darksalmon' => 'E9967A',
'darkseagreen' => '8FBC8F',
'darkslateblue' => '483D8B',
'darkslategray' => '2F4F4F',
'darkslategrey' => '2F4F4F',
'darkturquoise' => '00CED1',
'darkviolet' => '9400D3',
'deeppink' => 'FF1493',
'deepskyblue' => '00BFFF',
'dimgray' => '696969',
'dimgrey' => '696969',
'dodgerblue' => '1E90FF',
'firebrick' => 'B22222',
'floralwhite' => 'FFFAF0',
'forestgreen' => '228B22',
'fuchsia' => 'FF00FF',
'gainsboro' => 'DCDCDC',
'ghostwhite' => 'F8F8FF',
'gold' => 'FFD700',
'goldenrod' => 'DAA520',
'gray' => '808080',
'green' => '008000',
'greenyellow' => 'ADFF2F',
'grey' => '808080',
'honeydew' => 'F0FFF0',
'hotpink' => 'FF69B4',
'indianred' => 'CD5C5C',
'indigo' => '4B0082',
'ivory' => 'FFFFF0',
'khaki' => 'F0E68C',
'lavender' => 'E6E6FA',
'lavenderblush' => 'FFF0F5',
'lawngreen' => '7CFC00',
'lemonchiffon' => 'FFFACD',
'lightblue' => 'ADD8E6',
'lightcoral' => 'F08080',
'lightcyan' => 'E0FFFF',
'lightgoldenrodyellow' => 'FAFAD2',
'lightgray' => 'D3D3D3',
'lightgreen' => '90EE90',
'lightgrey' => 'D3D3D3',
'lightpink' => 'FFB6C1',
'lightsalmon' => 'FFA07A',
'lightseagreen' => '20B2AA',
'lightskyblue' => '87CEFA',
'lightslategray' => '778899',
'lightslategrey' => '778899',
'lightsteelblue' => 'B0C4DE',
'lightyellow' => 'FFFFE0',
'lime' => '00FF00',
'limegreen' => '32CD32',
'linen' => 'FAF0E6',
'magenta' => 'FF00FF',
'maroon' => '800000',
'mediumaquamarine' => '66CDAA',
'mediumblue' => '0000CD',
'mediumorchid' => 'BA55D3',
'mediumpurple' => '9370D0',
'mediumseagreen' => '3CB371',
'mediumslateblue' => '7B68EE',
'mediumspringgreen' => '00FA9A',
'mediumturquoise' => '48D1CC',
'mediumvioletred' => 'C71585',
'midnightblue' => '191970',
'mintcream' => 'F5FFFA',
'mistyrose' => 'FFE4E1',
'moccasin' => 'FFE4B5',
'navajowhite' => 'FFDEAD',
'navy' => '000080',
'oldlace' => 'FDF5E6',
'olive' => '808000',
'olivedrab' => '6B8E23',
'orange' => 'FFA500',
'orangered' => 'FF4500',
'orchid' => 'DA70D6',
'palegoldenrod' => 'EEE8AA',
'palegreen' => '98FB98',
'paleturquoise' => 'AFEEEE',
'palevioletred' => 'DB7093',
'papayawhip' => 'FFEFD5',
'peachpuff' => 'FFDAB9',
'peru' => 'CD853F',
'pink' => 'FFC0CB',
'plum' => 'DDA0DD',
'powderblue' => 'B0E0E6',
'purple' => '800080',
'red' => 'FF0000',
'rosybrown' => 'BC8F8F',
'royalblue' => '4169E1',
'saddlebrown' => '8B4513',
'salmon' => 'FA8072',
'sandybrown' => 'F4A460',
'seagreen' => '2E8B57',
'seashell' => 'FFF5EE',
'sienna' => 'A0522D',
'silver' => 'C0C0C0',
'skyblue' => '87CEEB',
'slateblue' => '6A5ACD',
'slategray' => '708090',
'slategrey' => '708090',
'snow' => 'FFFAFA',
'springgreen' => '00FF7F',
'steelblue' => '4682B4',
'tan' => 'D2B48C',
'teal' => '008080',
'thistle' => 'D8BFD8',
'tomato' => 'FF6347',
'turquoise' => '40E0D0',
'violet' => 'EE82EE',
'wheat' => 'F5DEB3',
'white' => 'FFFFFF',
'whitesmoke' => 'F5F5F5',
'yellow' => 'FFFF00',
'yellowgreen' => '9ACD32',
);
if ( is_array( $color ) ) {
$color = $color[0];
}
// Remove any spaces and special characters before and after the string.
$color = trim( $color );
// Check if the color is a standard word-color.
// If it is, then convert to hex.
if ( array_key_exists( $color, $word_colors ) ) {
$color = $word_colors[ $color ];
}
// Remove any trailing '#' symbols from the color value.
$color = str_replace( '#', '', $color );
// If the string is six characters long, then use it in pairs.
if ( 3 === strlen( $color ) ) {
$color = substr( $color, 0, 1 ) . substr( $color, 0, 1 ) . substr( $color, 1, 1 ) . substr( $color, 1, 1 ) . substr( $color, 2, 1 ) . substr( $color, 2, 1 );
}
$substr = array();
for ( $i = 0; $i <= 5; $i++ ) {
$default = ( 0 === $i ) ? 'F' : ( $substr[ $i - 1 ] );
$substr[ $i ] = substr( $color, $i, 1 );
$substr[ $i ] = ( false === $substr[ $i ] || ! ctype_xdigit( $substr[ $i ] ) ) ? $default : $substr[ $i ];
}
$hex = implode( '', $substr );
return ( ! $hash ) ? $hex : '#' . $hex;
}
/**
* Sanitizes RGBA color.
*
* @param string $value RGBA value.
*
* @return string
*/
public static function sanitize_rgba( string $value ): string {
// If empty or an array return transparent.
if ( empty( $value ) ) {
return 'rgba(0,0,0,0)';
}
// If string does not start with 'rgba', then treat as hex
// sanitize the hex color and finally convert hex to rgba.
if ( false === strpos( $value, 'rgba' ) ) {
return self::get_rgba( self::sanitize_hex( $value ) );
}
// By now we know the string is formatted as a rgba color, so we can just return it.
$value = str_replace( array( ' ', 'rgba', '(', ')' ), '', $value );
$value = explode( ',', $value );
$red = ( isset( $value[0] ) ) ? intval( $value[0] ) : 255;
$green = ( isset( $value[1] ) ) ? intval( $value[1] ) : 255;
$blue = ( isset( $value[2] ) ) ? intval( $value[2] ) : 255;
$alpha = ( isset( $value[3] ) ) ? filter_var( $value[3], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ) : 1;
return 'rgba(' . $red . ',' . $green . ',' . $blue . ',' . $alpha . ')';
}
/**
* Sanitize colors.
* Determine if the current value is a hex or a rgba color and call the appropriate method.
*
* @param string|array $value hex or rgba color.
*
* @return string
* @since 0.8.5
*/
public static function sanitize_color( $value ): string {
if ( is_array( $value ) ) {
if ( isset( $value['rgba'] ) ) {
$value = $value['rgba'];
} elseif ( isset( $value['color'] ) ) {
$opacity = ( isset( $value['opacity'] ) ) ? $value['opacity'] : null;
$opacity = ( ! is_null( $opacity ) && isset( $value['alpha'] ) ) ? $value['alpha'] : null;
$opacity = ( is_null( $opacity ) ) ? 1 : floatval( $opacity );
$value = self::get_rgba( $value['color'], $opacity );
} else {
return '';
}
}
if ( 'transparent' === $value ) {
return 'transparent';
}
// Is this a rgba color or a hex?
$mode = ( false === strpos( $value, 'rgba' ) ) ? 'rgba' : 'hex';
if ( 'rgba' === $mode ) {
return self::sanitize_hex( $value );
} else {
return self::sanitize_rgba( $value );
}
}
/**
* Gets the rgb value of the $hex color.
*
* @param string $hex The hex value of a color.
* @param boolean $implode Whether we want to implode the values or not.
*
* @return array|string array|string
*/
public static function get_rgb( string $hex, bool $implode = false ) {
// Remove any trailing '#' symbols from the color value.
$hex = self::sanitize_hex( $hex, false );
// rgb is an array.
$rgb = array(
hexdec( substr( $hex, 0, 2 ) ),
hexdec( substr( $hex, 2, 2 ) ),
hexdec( substr( $hex, 4, 2 ) ),
);
return ( $implode ) ? implode( ',', $rgb ) : $rgb;
}
/**
* Gets the rgb value of the $hex color.
*
* @param string $hex The hex value of a color.
* @param int $opacity Opacity level (1-100).
*
* @return string
*/
public static function get_rgba( string $hex = '#fff', int $opacity = 100 ): string {
$hex = self::sanitize_hex( $hex, false );
/**
* Make sure that opacity is properly formatted:
* Set the opacity to 100 if a larger value has been entered by mistake.
* If a negative value is used, then set to 0.
* If an opacity value is entered in a decimal form (for example, 0.25), then multiply by 100.
*/
if ( $opacity >= 100 ) {
$opacity = 100;
} elseif ( $opacity < 0 ) {
$opacity = 0;
} elseif ( $opacity <= 1 && 0 !== $opacity ) {
$opacity = ( $opacity * 100 );
}
// Divide the opacity by 100 to end-up with a CSS value for the opacity.
$opacity = ( $opacity / 100 );
return 'rgba(' . self::get_rgb( $hex, true ) . ', ' . $opacity . ')';
}
}
}

View File

@@ -0,0 +1,412 @@
<?php
/**
* Redux Connection Banner Class
*
* @class Redux_Core
* @version 4.0.0
* @package Redux Framework
*/
// @codingStandardsIgnoreStart
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Connection_Banner', false ) ) {
/**
* Class Redux_Connection_Banner
*/
class Redux_Connection_Banner {
/**
* Plugin version, used for cache-busting of style and script file references.
*
* @since 1.0.0
* @var string
*/
protected $version = '1.0.0';
/**
* Singleton instance.
*
* @var Redux_Connection_Banner
**/
private static $instance = null;
/**
* Register option.
*
* @var string $register_option
*/
private $register_option = 'redux-connection-register';
/**
* Dismiss option.
*
* @var string $dismiss_option
*/
private $dismiss_option = 'redux-connection-dismiss';
/**
* Nonce slug.
*
* @var string $dismiss_options
*/
private $nonce = 'redux-connection-nonce';
/**
* URLs.
*
* @var array $urls
*/
private $urls = array();
/**
* Init function.
*
* @return Redux_Connection_Banner
*/
public static function init(): ?Redux_Connection_Banner {
if ( is_null( self::$instance ) ) {
self::$instance = new Redux_Connection_Banner();
}
return self::$instance;
}
/**
* Redux_Connection_Banner constructor.
*
* Since we call the Redux_Connection_Banner:init() method from the `Redux` class, and after
* the admin_init action fires, we know that the admin is initialized at this point.
*/
private function __construct() {
$clean_get = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $clean_get['_wpnonce'] ) && wp_verify_nonce( $clean_get['_wpnonce'], $this->nonce ) ) {
if ( isset( $clean_get[ $this->dismiss_option ] ) ) {
update_option( 'redux-framework_extendify_plugin_notice', 'hide' );
return;
}
}
add_action( 'wp_ajax_redux_activation', array( $this, 'admin_ajax' ) ); // Executed when logged in.
add_action( 'current_screen', array( $this, 'maybe_initialize_hooks' ) );
}
/**
* Get the URL for the current page to fall back if JS is broken.
*
* @param bool|string $location Used to determine the location of the banner for account creation.
* @since 4.1.21
* @return array
*/
private function get_urls( $location = true ): array {
if ( ! empty( $this->urls ) ) {
return $this->urls;
}
global $pagenow;
$clean_get = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $clean_get[ $this->register_option ] ) ) {
unset( $clean_get[ $this->register_option ] );
}
if ( isset( $clean_get[ $this->dismiss_option ] ) ) {
unset( $clean_get[ $this->dismiss_option ] );
}
$base_url = admin_url( add_query_arg( $clean_get, $pagenow ) );
return array(
'dismiss' => wp_nonce_url( add_query_arg( $this->dismiss_option, true, $base_url ), $this->nonce ),
'register' => wp_nonce_url( add_query_arg( $this->register_option, $location, $base_url ), $this->nonce ),
);
}
/**
* AJAX callback for dismissing the notice.
*/
public function admin_ajax() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, $this->nonce ) ) {
die( __( 'Security check failed.', 'redux-framework' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
if ( 'false' === $_REQUEST['activate'] ) {
echo wp_json_encode(
array(
'type' => 'close',
'msg' => '',
)
);
update_option( 'redux-framework_extendify_plugin_notice', 'hide' );
die();
}
$res = $this->install_extendify();
if ( true === $res ) {
update_option( 'redux-framework_extendify_plugin_notice', 'hide' );
}
die();
}
/**
* Install and activate Extendify Plugin.
*
* @return bool
*/
private function install_extendify(): bool {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/misc.php';
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$api = plugins_api(
'plugin_information',
array(
'slug' => 'extendify',
'fields' => array(
'short_description' => false,
'sections' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'donate_link' => false,
),
)
);
$download_link = $api->download_link;
if ( empty( $download_link ) ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'Error: Install URL for Extendify could not be located.', 'redux-framework' ),
)
);
return false;
}
ob_start();
$skin = new Redux_Installer_Muter( array( 'api' => $api ) );
$upgrader = new Plugin_Upgrader( $skin );
$install = $upgrader->install( $download_link );
if ( ob_get_contents() ) {
ob_end_clean();
}
if ( true !== $install ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'Install process for Extendify failed.', 'redux-framework' ),
)
);
return false;
}
$plugin_dir = WP_PLUGIN_DIR . '/extendify/extendify.php';
$activate = activate_plugin( $plugin_dir );
if ( is_wp_error( $activate ) ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'Extendify activation failed.', 'redux-framework' ),
)
);
}
echo wp_json_encode(
array(
'type' => 'success',
'msg' => esc_html__( 'Extendify installed and activated.', 'redux-framework' ),
)
);
return true;
}
/**
* AJAX callback for dismissing the notice.
*
* @param string|null $admin_body_class Class string.
*
* @return string
*/
public function admin_body_class( ?string $admin_body_class = '' ): string {
$classes = explode( ' ', trim( $admin_body_class ) );
$classes[] = false ? 'redux-connected' : 'redux-disconnected';
$admin_body_class = implode( ' ', array_unique( $classes ) );
return " $admin_body_class ";
}
/**
* Will initialize hooks to display the new (as of 4.4) connection banner if the current user can
* connect Redux if Redux has not been deactivated, and if the current page is the plugin page.
*
* This method should not be called if the site is connected to WordPress.com or if the site is in development mode.
*
* @since 4.4.0
* @since 4.5.0 Made the new (as of 4.4) connection banner display to everyone by default.
* @since 5.3.0 Running another split test between 4.4 banner and a new one in 5.3.
* @since 7.2 B test was removed.
*
* @param $current_screen
*/
public function maybe_initialize_hooks( $current_screen ) {
if ( Redux_Functions_Ex::is_plugin_installed( 'extendify' ) || 'hide' === get_option( 'redux-framework_extendify_plugin_notice', null ) ) {
return;
}
if ( ! current_user_can( 'install_plugins' ) ) {
return;
}
// Don't show the connection notice anywhere but the plugins.php after activating
if ( 'plugins' !== $current_screen->base && 'dashboard' !== $current_screen->base ) {
add_action( 'admin_head', array( $this, 'admin_head' ) );
return;
}
// Only show this notice when the plugin is installed.
if ( class_exists( 'Redux_Framework_Plugin' ) && false === Redux_Framework_Plugin::$crash ) {
add_action( 'admin_notices', array( $this, 'render_banner' ) );
add_action( 'network_admin_notices', array( $this, 'network_connect_notice' ) );
add_action( 'admin_head', array( $this, 'admin_head' ) );
add_filter( 'admin_body_class', array( $this, 'admin_body_class' ), 20 );
}
}
/**
* Hide Individual Dashboard Pages
*
* @access public
* @since 4.0.0
* @return void
*/
public function admin_head() {
?>
<link
rel='stylesheet' id='redux-banner' <?php // phpcs:ignore WordPress.WP.EnqueuedResources ?>
href='<?php echo esc_url( Redux_Core::$url ); ?>inc/welcome/css/redux-banner.min.css'
type='text/css' media='all'/>
<script
id="redux-banner-admin"
src='<?php echo esc_url( Redux_Core::$url ); ?>inc/welcome/js/redux-banner-admin.min.js'>
</script>
<?php
}
/**
* Renders the new connection banner as of 4.4.0.
*
* @since 7.2 Copy and visual elements reduced to show the new focus of Redux on Security and Performance.
* @since 4.4.0
*/
public function render_banner() {
$urls = $this->get_urls( 'main_banner' );
?>
<div id="redux-connect-message" class="updated redux-banner-container" data-nonce="<?php echo wp_create_nonce( $this->nonce ); ?>">
<div class="redux-banner-inner-container">
<a href="<?php echo esc_url( $urls['dismiss'] ); ?>" data-url="<?php echo admin_url( 'admin-ajax.php' ); ?>"
class="notice-dismiss redux-banner-svg-dismiss redux-connection-banner-action"
title="<?php esc_attr_e( 'Dismiss this notice', 'redux-framework' ); ?>" data-activate="false">
</a>
<div class="redux-banner-content-container">
<!-- slide 1: intro -->
<div class="redux-banner-slide redux-banner-slide-one redux-slide-is-active">
<div class="redux-banner-content-icon redux-illo">
<a href="<?php echo esc_url( 'https://redux.io/?utm_source=plugin&utm_medium=extendify-plugin&utm_campaign=redux_banner_logo' ); ?>" target="_blank"><img
src="<?php echo esc_url( Redux_Core::$url ); ?>assets/img/logo-color.svg"
class="redux-banner-content-logo"
alt="
<?php
esc_attr_e(
'Visit our website to learn more!',
'redux-framework'
);
?>
" height="auto"
/></a>
</div>
<div class="redux-banner-slide-text">
<h2><?php esc_html_e( 'Action needed to continue using the template library.', 'redux-framework' ); ?></h2>
<p>
<?php
esc_html_e(
"The Extendify Library of Patterns and Templates has been unbundled from the Redux Options Framework to give our users more control over their WordPress experience. To continue using the Extendify Library click Install & Activate below.",
'redux_framework'
);
?>
</p>
<div class="redux-banner-button-container">
<span class="redux-banner-tos-blurb"></span>
<a href="<?php echo esc_url( $urls['register'] ); ?>" data-url="<?php echo admin_url( 'admin-ajax.php' ); ?>" data-activate="main_banner"
class="button button-primary button-large redux-alt-connect-button redux-connection-banner-action">
<?php esc_html_e( 'Install and Activate Extendify', 'redux-framework' ); ?>
</a>
</div>
</div>
</div> <!-- end slide 1 -->
</div>
</div>
</div>
<noscript><style>#redux-connect-message{display:none;}</style></noscript>
<?php
}
/**
* Renders the legacy network connection banner.
*/
public function network_connect_notice() {
?>
<div id="message" class="updated Redux-message">
<div class="squeezer">
<h2>
<?php
echo wp_kses(
__(
'<strong>Redux is activated!</strong> Each site on your network must be connected individually by an admin on that site.',
'Redux'
),
array( 'strong' => array() )
);
?>
</h2>
</div>
</div>
<noscript><style>#message{display:none;}</style></noscript>
<?php
}
}
}
// @codingStandardsIgnoreEnd

View File

@@ -0,0 +1,737 @@
<?php
/**
* Redux Primary Enqueue Class
*
* @class Redux_Core
* @version 4.0.0
* @package Redux Framework/Classes
* @noinspection PhpIgnoredClassAliasDeclaration
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Enqueue', false ) ) {
/**
* Class Redux_Enqueue
*/
class Redux_Enqueue extends Redux_Class {
/**
* Data to localize.
*
* @var array
*/
public $localize_data = array();
/**
* Min string for .min files.
*
* @var string
*/
private $min = '';
/**
* Timestamp for file versions.
*
* @var string
*/
private $timestamp = '';
/**
* Localize data required for the repeater extension.
*
* @var array
*/
private $repeater_data = array();
/**
* Redux_Enqueue constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
// Enqueue the admin page CSS and JS.
if ( isset( $_GET['page'] ) && $_GET['page'] === $redux->args['page_slug'] ) { // phpcs:ignore WordPress.Security.NonceVerification
add_action( 'admin_enqueue_scripts', array( $this, 'init' ), 1 );
}
add_action( 'wp_enqueue_scripts', array( $this, 'frontend_init' ), 10 );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/{$redux->args['opt_name']}/enqueue/construct", $this );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/enqueue/construct', $this );
}
/**
* Scripts to enqueue on the frontend
*/
public function frontend_init() {
$core = $this->core();
if ( $core->args['elusive_frontend'] ) {
Redux_Functions_Ex::enqueue_elusive_font();
}
if ( $core->args['fontawesome_frontend'] ) {
Redux_Functions_Ex::enqueue_font_awesome();
}
}
/**
* Class init functions.
*/
public function init() {
$core = $this->core();
Redux_Functions::$parent = $core;
Redux_CDN::$parent = $core;
$this->min = Redux_Functions::is_min();
$this->timestamp = Redux_Core::$version;
if ( $core->args['dev_mode'] ) {
$this->timestamp .= '.' . time();
}
$this->register_styles( $core );
$this->register_scripts();
add_thickbox();
$this->enqueue_fields( $core );
add_filter( "redux/{$core->args['opt_name']}/localize", array( 'Redux_Helpers', 'localize' ) );
$this->set_localized_data( $core );
/**
* Action 'redux/page/{opt_name}/enqueue'
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/page/{$core->args['opt_name']}/enqueue" );
}
/**
* Register all core framework styles.
*
* @param object $core ReduxFramework object.
*/
private function register_styles( $core ) {
/**
* Redux Admin CSS
*/
if ( 'wordpress' === $core->args['admin_theme'] || 'wp' === $core->args['admin_theme'] ) { // phpcs:ignore WordPress.WP.CapitalPDangit
$color_scheme = get_user_option( 'admin_color' );
} elseif ( 'classic' === $core->args['admin_theme'] || '' === $core->args['admin_theme'] ) {
$color_scheme = 'classic';
} else {
$color_scheme = $core->args['admin_theme'];
}
if ( ! file_exists( Redux_Core::$dir . "assets/css/colors/$color_scheme/colors$this->min.css" ) ) {
$color_scheme = 'fresh';
}
$css = Redux_Core::$url . "assets/css/colors/$color_scheme/colors$this->min.css";
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$css = apply_filters( 'redux/enqueue/' . $core->args['opt_name'] . '/args/admin_theme/css_url', $css );
wp_register_style(
'redux-admin-theme',
$css,
array(),
$this->timestamp
);
wp_enqueue_style(
'redux-admin-css',
Redux_Core::$url . "assets/css/redux-admin$this->min.css",
array( 'redux-admin-theme' ),
$this->timestamp
);
/**
* Redux Fields CSS
*/
if ( ! $core->args['dev_mode'] ) {
wp_enqueue_style(
'redux-fields',
Redux_Core::$url . 'assets/css/redux-fields.min.css',
array(),
$this->timestamp
);
}
/**
* Select2 CSS
*/
wp_enqueue_style(
'select2-css',
Redux_Core::$url . 'assets/css/vendor/select2.min.css',
array(),
'4.1.0'
);
/**
* Spectrum CSS
*/
wp_register_style(
'redux-spectrum-css',
Redux_Core::$url . "assets/css/vendor/spectrum$this->min.css",
array(),
'1.3.3'
);
/**
* Elusive Icon CSS
*/
Redux_Functions_Ex::enqueue_elusive_font();
/**
* Font Awesome for Social Profiles and Icon Select
*/
Redux_Functions_Ex::enqueue_font_awesome();
/**
* QTip CSS
*/
wp_enqueue_style(
'qtip',
Redux_Core::$url . "assets/css/vendor/qtip$this->min.css",
array(),
'3.0.3'
);
/**
* JQuery UI CSS
*/
wp_enqueue_style(
'jquery-ui',
// phpcs:ignore WordPress.NamingConventions.ValidHookName
apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/page/{$core->args['opt_name']}/enqueue/jquery-ui-css",
Redux_Core::$url . 'assets/css/vendor/jquery-ui-1.10.0.custom.css'
),
array(),
$this->timestamp
);
/**
* Iris CSS
*/
wp_enqueue_style( 'wp-color-picker' );
if ( $core->args['dev_mode'] ) {
/**
* Media CSS
*/
wp_enqueue_style(
'redux-field-media',
Redux_Core::$url . 'assets/css/media.css',
array(),
$this->timestamp
);
}
/**
* RTL CSS
*/
if ( is_rtl() ) {
wp_enqueue_style(
'redux-rtl',
Redux_Core::$url . 'assets/css/rtl.css',
array(),
$this->timestamp
);
}
}
/**
* Register all core framework scripts.
*/
private function register_scripts() {
// *****************************************************************
// JQuery / JQuery UI JS
// *****************************************************************
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'jquery-ui-core' );
wp_enqueue_script( 'jquery-ui-dialog' );
/**
* Select2 Sortable JS
*/
wp_register_script(
'redux-select2-sortable',
Redux_Core::$url . 'assets/js/vendor/select2-sortable/redux.select2.sortable' . $this->min . '.js',
array( 'jquery', 'jquery-ui-sortable' ),
$this->timestamp,
true
);
/**
* Select2
*/
wp_enqueue_script(
'select2-js',
Redux_Core::$url . 'assets/js/vendor/select2/select2' . $this->min . '.js`',
array( 'jquery', 'redux-select2-sortable' ),
'4.1.0',
true
);
/**
* QTip JS
*/
wp_enqueue_script(
'qtip',
Redux_Core::$url . 'assets/js/vendor/qtip/qtip' . $this->min . '.js',
array( 'jquery' ),
'3.0.3',
true
);
/**
* Iris alpha color picker
*/
if ( ! wp_script_is( 'redux-wp-color-picker-alpha' ) ) {
wp_enqueue_style( 'wp-color-picker' );
wp_register_script(
'redux-wp-color-picker-alpha',
Redux_Core::$url . 'assets/js/vendor/wp-color-picker-alpha/wp-color-picker-alpha' . $this->min . '.js',
array( 'jquery', 'wp-color-picker' ),
'3.0.0',
true
);
}
/**
* Block UI (used by Custom Fonts and Color Schemes).
*/
wp_register_script(
'redux-block-ui',
Redux_Core::$url . 'assets/js/vendor/block-ui/jquery.blockUI' . $this->min . '.js',
array( 'jquery' ),
'2.70.0',
true
);
/**
* Spectrum JS
*/
wp_register_script(
'redux-spectrum-js',
Redux_Core::$url . 'assets/js/vendor/spectrum/redux-spectrum' . $this->min . '.js',
array( 'jquery' ),
'1.3.3',
true
);
/**
* Vendor JS
*/
wp_register_script(
'redux-vendor',
Redux_Core::$url . 'assets/js/redux-vendors' . $this->min . '.js',
array( 'jquery' ),
$this->timestamp,
true
);
/**
* Redux JS
*/
wp_register_script(
'redux-js',
Redux_Core::$url . 'assets/js/redux' . $this->min . '.js',
array( 'jquery', 'redux-vendor' ),
$this->timestamp,
true
);
}
/**
* Enqueue fields that are in use.
*
* @param object $core ReduxFramework object.
* @param array $field Field array.
*/
public function enqueue_field( $core, array $field ) {
if ( isset( $field['type'] ) && 'callback' !== $field['type'] ) {
$field_type = str_replace( '_', '-', $field['type'] );
$core_path = Redux_Core::$dir . "inc/fields/{$field['type']}/class-redux-$field_type.php";
// Shim for v3 extension class names.
if ( ! file_exists( $core_path ) ) {
$core_path = Redux_Core::$dir . "inc/fields/{$field['type']}/field_{$field['type']}.php";
}
$filter_path = $core_path;
/**
* Field class file
* filter 'redux/{opt_name}/field/class/{field.type}
*
* @param string $filter_path Field class file path
* @param array $field Field config data
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$class_file = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/field/class/{$field['type']}",
$filter_path,
$field
);
$field_classes = array( 'Redux_' . $field['type'], 'ReduxFramework_' . $field['type'] );
if ( $class_file ) {
$field_class = Redux_Functions::class_exists_ex( $field_classes );
if ( false === $field_class ) {
if ( file_exists( $class_file ) ) {
require_once $class_file;
$field_class = Redux_Functions::class_exists_ex( $field_classes );
} else {
return;
}
}
if ( false !== $field_class && ( ( method_exists( $field_class, 'enqueue' ) ) || method_exists( $field_class, 'localize' ) ) ) {
if ( ! isset( $core->options[ $field['id'] ] ) ) {
$core->options[ $field['id'] ] = '';
}
$the_field = new $field_class( $field, $core->options[ $field['id'] ], $core );
// Move dev_mode check to a new if/then block.
if ( ! wp_script_is( 'redux-field-' . $field_type ) && ( class_exists( $field_class ) && method_exists( $field_class, 'enqueue' ) ) ) {
$the_field->enqueue();
}
if ( class_exists( $field_class ) && method_exists( $field_class, 'always_enqueue' ) ) {
$the_field->always_enqueue();
}
if ( method_exists( $field_class, 'localize' ) ) {
$the_field->localize( $field );
if ( ! isset( $this->localize_data[ $field['type'] ] ) ) {
$this->localize_data[ $field['type'] ] = array();
}
$localize_data = $the_field->localize( $field );
$shims = array( 'repeater' );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$shims = apply_filters( 'redux/' . $core->args['opt_name'] . '/localize/shims', $shims );
if ( is_array( $shims ) && in_array( $field['type'], $shims, true ) ) {
$this->repeater_data[ $field['type'] ][ $field['id'] ] = $localize_data;
}
$this->localize_data[ $field['type'] ][ $field['id'] ] = $localize_data;
}
unset( $the_field );
}
}
}
}
/**
* Enqueue field files.
*
* @param object $core ReduxFramework object.
*/
private function enqueue_fields( $core ) {
foreach ( $core->sections as $section ) {
if ( isset( $section['fields'] ) ) {
foreach ( $section['fields'] as $field ) {
$this->enqueue_field( $core, $field );
}
}
}
}
/**
* Build a localized array from field functions, if any.
*
* @param object $core ReduxFramework object.
* @param string $type Field type.
*/
private function build_local_array( $core, string $type ) {
if ( isset( $core->transients['last_save_mode'] ) && ! empty( $core->transients['notices'][ $type ] ) ) {
$the_total = 0;
$messages = array();
foreach ( $core->transients['notices'][ $type ] as $msg ) {
if ( is_array( $msg ) && ! empty( $msg ) ) {
$messages[ $msg['section_id'] ][ $type ][] = $msg;
if ( ! isset( $messages[ $msg['section_id'] ]['total'] ) ) {
$messages[ $msg['section_id'] ]['total'] = 0;
}
++$messages[ $msg['section_id'] ]['total'];
++$the_total;
}
}
$this->localize_data[ $type ] = array(
'total' => $the_total,
"$type" => $messages,
);
unset( $core->transients['notices'][ $type ] );
}
}
/**
* Compile panel errors and wearings for a localized array.
*/
public function get_warnings_and_errors_array() {
$core = $this->core();
$this->build_local_array( $core, 'errors' );
$this->build_local_array( $core, 'warnings' );
$this->build_local_array( $core, 'sanitize' );
if ( empty( $core->transients['notices'] ) ) {
if ( isset( $core->transients['notices'] ) ) {
unset( $core->transients['notices'] );
}
}
}
/**
* Commit localized data to global array.
*
* @param object $core ReduxFramework object.
*/
private function set_localized_data( $core ) {
if ( ! empty( $core->args['last_tab'] ) ) {
$this->localize_data['last_tab'] = $core->args['last_tab'];
}
$this->localize_data['font_weights'] = $this->args['font_weights'];
$this->localize_data['required'] = $core->required;
$this->repeater_data['fonts'] = $core->fonts;
if ( ! isset( $this->repeater_data['opt_names'] ) ) {
$this->repeater_data['opt_names'] = array();
}
$this->repeater_data['opt_names'][] = $core->args['opt_name'];
$this->repeater_data['folds'] = array();
$this->localize_data['required_child'] = $core->required_child;
$this->localize_data['fields'] = $core->fields;
if ( isset( $core->font_groups['google'] ) ) {
$this->repeater_data['googlefonts'] = $core->font_groups['google'];
}
if ( isset( $core->font_groups['std'] ) ) {
$this->repeater_data['stdfonts'] = $core->font_groups['std'];
}
if ( isset( $core->font_groups['customfonts'] ) ) {
$this->repeater_data['customfonts'] = $core->font_groups['customfonts'];
}
if ( isset( $core->font_groups['typekitfonts'] ) ) {
$this->repeater_data['typekitfonts'] = $core->font_groups['typekitfonts'];
}
$this->localize_data['folds'] = $core->folds;
// Make sure the children are all hidden properly.
foreach ( $core->fields as $key => $value ) {
if ( in_array( $key, $core->fields_hidden, true ) ) {
foreach ( $value as $k => $v ) {
if ( ! in_array( $k, $core->fields_hidden, true ) ) {
$core->fields_hidden[] = $k;
$core->folds[ $k ] = 'hide';
}
}
}
}
$this->localize_data['fields_hidden'] = $core->fields_hidden;
$this->localize_data['options'] = $core->options;
$this->localize_data['defaults'] = $core->options_defaults;
/**
* Save pending string
* filter 'redux/{opt_name}/localize/save_pending
*
* @param string $msg Save_pending string
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$save_pending = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/localize/save_pending",
esc_html__(
'You have changes that are not saved. Would you like to save them now?',
'redux-framework'
)
);
/**
* Reset all string
* filter 'redux/{opt_name}/localize/reset
*
* @param string $msg Reset all string.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$reset_all = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/localize/reset",
esc_html__(
'Are you sure? Resetting will lose all custom values.',
'redux-framework'
)
);
/**
* Reset section string
* filter 'redux/{opt_name}/localize/reset_section
*
* @param string $msg Reset section string.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$reset_section = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/localize/reset_section",
esc_html__(
'Are you sure? Resetting will lose all custom values in this section.',
'redux-framework'
)
);
/**
* Preset confirm string
* filter 'redux/{opt_name}/localize/preset
*
* @param string $msg Preset confirm string.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$preset_confirm = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/localize/preset",
esc_html__(
'Your current options will be replaced with the values of this preset. Would you like to proceed?',
'redux-framework'
)
);
/**
* Import confirm string
* filter 'redux/{opt_name}/localize/import
*
* @param string $msg Import confirm string.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$import_confirm = apply_filters(
// phpcs:ignore WordPress.NamingConventions.ValidHookName
"redux/{$core->args['opt_name']}/localize/import",
esc_html__(
'Your current options will be replaced with the values of this import. Would you like to proceed?',
'redux-framework'
)
);
global $pagenow;
$this->localize_data['args'] = array(
'dev_mode' => $core->args['dev_mode'],
'save_pending' => $save_pending,
'reset_confirm' => $reset_all,
'reset_section_confirm' => $reset_section,
'preset_confirm' => $preset_confirm,
'import_section_confirm' => $import_confirm,
'please_wait' => esc_html__( 'Please Wait', 'redux-framework' ),
'opt_name' => $core->args['opt_name'],
'flyout_submenus' => $core->args['flyout_submenus'] ?? false,
'slug' => $core->args['page_slug'],
'hints' => $core->args['hints'],
'disable_save_warn' => $core->args['disable_save_warn'],
'class' => $core->args['class'],
'ajax_save' => $core->args['ajax_save'],
'menu_search' => $pagenow . '?page=' . $core->args['page_slug'] . '&tab=',
);
$this->localize_data['ajax'] = array(
'console' => esc_html__(
'There was an error saving. Here is the result of your action:',
'redux-framework'
),
'alert' => esc_html__(
'There was a problem with your action. Please try again or reload the page.',
'redux-framework'
),
);
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$this->localize_data = apply_filters( "redux/{$core->args['opt_name']}/localize", $this->localize_data );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$this->repeater_data = apply_filters( "redux/{$core->args['opt_name']}/repeater", $this->repeater_data );
$this->get_warnings_and_errors_array();
if ( ! isset( $core->repeater_data ) ) {
$core->repeater_data = array();
}
$core->repeater_data = Redux_Functions_Ex::nested_wp_parse_args(
$this->repeater_data,
$core->repeater_data
);
if ( ! isset( $core->localize_data ) ) {
$core->localize_data = array();
}
$core->localize_data = Redux_Functions_Ex::nested_wp_parse_args(
$this->localize_data,
$core->localize_data
);
// Shim for extension compatibility.
if ( Redux::$extension_compatibility ) {
$this->repeater_data = Redux_Functions_Ex::nested_wp_parse_args(
$this->repeater_data,
$core->localize_data
);
}
wp_localize_script(
'redux-js',
'redux',
$this->repeater_data
);
wp_localize_script(
'redux-js',
'redux_' . str_replace( '-', '_', $core->args['opt_name'] ),
$this->localize_data
);
wp_enqueue_script( 'redux-js' ); // Enqueue the JS now.
}
}
}
if ( ! class_exists( 'reduxCoreEnqueue' ) ) {
class_alias( 'Redux_Enqueue', 'reduxCoreEnqueue' );
}

View File

@@ -0,0 +1,245 @@
<?php
/**
* Redux Extension Abstract
*
* @class Redux_Extension_Abstract
* @version 4.0.0
* @package Redux Framework/Classes
* @noinspection PhpUnused
*/
defined( 'ABSPATH' ) || exit;
/**
* Class Redux_Extension_Abstract
* An abstract class to make the writing of redux extensions easier by allowing users to extend this class
*
* @see the samples directory to find a usage example
*/
abstract class Redux_Extension_Abstract {
/**
* The version of the extension (This is a default value you may want to override it)
*
* @var string
*/
public static $version = '1.0.0';
/**
* The extension URL.
*
* @var string
*/
protected $extension_url;
/**
* The extension dir.
*
* @var string
*/
protected $extension_dir;
/**
* The instance of the extension
*
* @var static
*/
protected static $instance;
/**
* The extension's file
*
* @var string
*/
protected $file;
/**
* The redux framework instance that spawned the extension.
*
* @var ReduxFramework
*/
public $parent;
/**
* The ReflectionClass of the extension
*
* @var ReflectionClass
*/
protected $reflection_class;
/**
* Redux_Extension_Abstract constructor.
*
* @param object $redux ReduxFramework pointer.
* @param string $file Extension file.
*/
public function __construct( $redux, string $file = '' ) {
$this->parent = $redux;
// If the file is not given, make sure we have one.
if ( empty( $file ) ) {
$file = $this->get_reflection()->getFileName();
}
$this->file = $file;
$this->extension_dir = trailingslashit( str_replace( '\\', '/', dirname( $file ) ) );
$plugin_info = Redux_Functions_Ex::is_inside_plugin( $this->file );
if ( false !== $plugin_info ) {
$this->extension_url = trailingslashit( dirname( $plugin_info['url'] ) );
} else {
$theme_info = Redux_Functions_Ex::is_inside_theme( $this->file );
if ( false !== $theme_info ) {
$this->extension_url = trailingslashit( dirname( $theme_info['url'] ) );
}
}
static::$instance = $this;
}
/**
* Get the reflection class of the extension.
*
* @return ReflectionClass
*/
protected function get_reflection(): ReflectionClass {
if ( ! isset( $this->reflection_class ) ) {
$this->reflection_class = new ReflectionClass( $this );
}
return $this->reflection_class;
}
/**
* Return extension version.
*
* @return string
*/
public static function get_version(): string {
return static::$version;
}
/**
* Returns extension instance.
*
* @return Redux_Extension_Abstract
*/
public static function get_instance(): Redux_Extension_Abstract {
return static::$instance;
}
/**
* Return extension dir.
*
* @return string
*/
public function get_dir(): string {
return $this->extension_dir;
}
/**
* Returns extension URL
*
* @return string
*/
public function get_url(): string {
return $this->extension_url;
}
/**
* Adds the local field. (The use of add_field is recommended).
*
* @param string $field_name Name of field.
*/
protected function add_overload_field_filter( string $field_name ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
add_filter( 'redux/' . $this->parent->args['opt_name'] . '/field/class/' . $field_name, array( &$this, 'overload_field_path' ), 10, 2 );
}
/**
* Adds the local field to the extension and register it in the builder.
*
* @param string $field_name Name of field.
*/
protected function add_field( string $field_name ) {
$class = $this->get_reflection()->getName();
// phpcs:ignore WordPress.NamingConventions.ValidHookName
add_filter(
'redux/fields',
function ( $classes ) use ( $field_name, $class ) {
$classes[ $field_name ] = $class;
return $classes;
}
);
$this->add_overload_field_filter( $field_name );
}
/**
* Overload a field path.
*
* @param string $file Extension file.
* @param array $field Field array.
*
* @return string
*/
public function overload_field_path( string $file, array $field ): string {
$filename_fix = str_replace( '_', '-', $field['type'] );
$files = array(
trailingslashit( dirname( $this->file ) ) . $field['type'] . DIRECTORY_SEPARATOR . 'field_' . $field['type'] . '.php',
trailingslashit( dirname( $this->file ) ) . $field['type'] . DIRECTORY_SEPARATOR . 'class-redux-' . $filename_fix . '.php',
);
return Redux_Functions::file_exists_ex( $files );
}
/**
* Sets the minimum version of Redux to use. Displays a notice if requirements are not met.
*
* @param string $min_version Minimum version to evaluate.
* @param string $extension_version Extension version number.
* @param string $friendly_name Friend extension name for notice display.
*
* @return bool
*/
public function is_minimum_version( string $min_version = '', string $extension_version = '', string $friendly_name = '' ): bool {
$redux_ver = Redux_Core::$version;
if ( '' !== $min_version ) {
if ( version_compare( $redux_ver, $min_version ) < 0 ) {
// translators: %1$s Extension friendly name. %2$s: minimum Redux version.
$msg = '<strong>' . sprintf( esc_html__( 'The %1$s extension requires Redux Framework version %2$s or higher.', 'redux-framework' ), $friendly_name, $min_version ) . '</strong>&nbsp;&nbsp;' . esc_html__( 'You are currently running Redux Framework version ', 'redux-framework' ) . ' ' . $redux_ver . '.<br/><br/>' . esc_html__( 'This field will not render in your option panel, and features of this extension will not be available until the latest version of Redux Framework has been installed.', 'redux-framework' );
$data = array(
'parent' => $this->parent,
'type' => 'error',
'msg' => $msg,
'id' => $this->ext_name . '_notice_' . $extension_version,
'dismiss' => false,
);
if ( method_exists( 'Redux_Admin_Notices', 'set_notice' ) ) {
Redux_Admin_Notices::set_notice( $data );
} else {
echo '<div class="error">';
echo '<p>';
echo $msg; // phpcs:ignore WordPress.Security.EscapeOutput
echo '</p>';
echo '</div>';
}
return false;
}
}
return true;
}
}
if ( ! class_exists( 'Redux_Abstract_Extension' ) ) {
class_alias( 'Redux_Extension_Abstract', 'Redux_Abstract_Extension' );
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Register Extensions for use
*
* @package Redux Framework/Classes
* @since 3.0.0
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Extensions', false ) ) {
/**
* Class Redux_Extensions
*/
class Redux_Extensions extends Redux_Class {
/**
* Redux_Extensions constructor.
*
* @param object $redux ReduxFramework object pointer.
*
* @throws ReflectionException Exception.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
$this->load();
}
/**
* Class load functions.
*
* @throws ReflectionException For fallback.
*/
private function load() {
$core = $this->core();
$max = 1;
for ( $i = 1; $i <= $max; $i++ ) {
$path = Redux_Core::$dir . 'inc/extensions/';
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$path = apply_filters( 'redux/' . $core->args['opt_name'] . '/extensions/dir', $path );
/**
* Action 'redux/extensions/before'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/extensions/before', $core );
/**
* Action 'redux/extensions/{opt_name}/before'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/extensions/{$core->args['opt_name']}/before", $core );
if ( isset( $core->old_opt_name ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/extensions/' . $core->old_opt_name . '/before', $core );
}
require_once Redux_Core::$dir . 'inc/classes/class-redux-extension-abstract.php';
$path = untrailingslashit( $path );
Redux::set_extensions( $core->args['opt_name'], $path, true );
/**
* Action 'redux/extensions/{opt_name}'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/extensions/{$core->args['opt_name']}", $core );
if ( isset( $core->old_opt_name ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/extensions/' . $core->old_opt_name, $core );
}
}
}
}
}

View File

@@ -0,0 +1,230 @@
<?php
/**
* Redux Field Class
*
* @class Redux_Field
* @version 4.0.0
* @package Redux Framework/Classes
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Field', false ) ) {
/**
* Class Redux_Field
*/
abstract class Redux_Field {
/**
* CSS styling per field output/compiler.
*
* @var string
*/
public $style = null;
/**
* Class dir.
*
* @var string
*/
public $dir = null;
/**
* Class URL.
*
* @var string
*/
public $url = null;
/**
* Timestamp for ver append in dev_mode
*
* @var string
*/
public $timestamp = null;
/**
* ReduxFramework object pointer.
*
* @var ReduxFramework
*/
public $parent;
/**
* Field values.
*
* @var string|array
*/
public $field;
/**
* Value values.
*
* @var string|array
*/
public $value;
/**
* Select2 options.
*
* @var array
*/
public $select2_config = array();
/**
* Redux_Field constructor.
*
* @param array|string|null $field Field array.
* @param string|array|null $value Field values.
* @param null $redux ReduxFramework object pointer.
*
* @throws ReflectionException Comment.
*/
public function __construct( $field = array(), $value = null, $redux = null ) {
$this->parent = $redux;
$this->field = $field;
$this->value = $value;
$this->select2_config = array(
'width' => 'resolve',
'allowClear' => false,
'theme' => 'default',
);
$this->set_defaults();
$class_name = get_class( $this );
$reflector = new ReflectionClass( $class_name );
$path = $reflector->getFilename();
$path_info = Redux_Helpers::path_info( $path );
$this->dir = trailingslashit( dirname( $path_info['real_path'] ) );
$this->url = trailingslashit( dirname( $path_info['url'] ) );
$this->timestamp = Redux_Core::$version;
if ( $redux->args['dev_mode'] ) {
$this->timestamp .= '.' . time();
}
}
/**
* Media query compiler for Redux Pro,
*
* @param string $style_data CSS string.
*/
public function media_query( string $style_data = '' ) {
$query_arr = $this->field['media_query'];
$css = '';
if ( isset( $query_arr['queries'] ) ) {
foreach ( $query_arr['queries'] as $query ) {
$rule = $query['rule'] ?? '';
$selectors = $query['selectors'] ?? array();
if ( ! is_array( $selectors ) && '' !== $selectors ) {
$selectors = array( $selectors );
}
if ( '' !== $rule && ! empty( $selectors ) ) {
$selectors = implode( ',', $selectors );
$css .= '@media ' . $rule . '{';
$css .= $selectors . '{' . $style_data . '}';
$css .= '}';
}
}
} else {
return;
}
if ( isset( $query_arr['output'] ) && $query_arr['output'] ) {
$this->parent->outputCSS .= $css;
}
if ( isset( $query_arr['compiler'] ) && $query_arr['compiler'] ) {
$this->parent->compilerCSS .= $css;
}
}
/**
* CSS for field output, if set (Remove the noinpection line and fix this function when we drop support for PHP 7.1).
*
* @param string $style CSS string.
*
* @noinspection PhpMissingParamTypeInspection
*/
public function output( $style = '' ) {
if ( '' !== $style ) {
// Force output value into an array.
if ( isset( $this->field['output'] ) && ! is_array( $this->field['output'] ) ) {
$this->field['output'] = array( $this->field['output'] );
}
if ( ! empty( $this->field['output'] ) && is_array( $this->field['output'] ) ) {
if ( isset( $this->field['output']['important'] ) ) {
if ( $this->field['output']['important'] ) {
$style = str_replace( ';', ' !important;', $style );
}
unset( $this->field['output']['important'] );
}
$keys = implode( ',', $this->field['output'] );
$this->parent->outputCSS .= $keys . '{' . $style . '}';
}
// Force compiler value into an array.
if ( isset( $this->field['compiler'] ) && ! is_array( $this->field['compiler'] ) ) {
$this->field['compiler'] = array( $this->field['compiler'] );
}
if ( isset( $this->field['compiler']['important'] ) ) {
if ( $this->field['compiler']['important'] ) {
$style = str_replace( ';', ' !important;', $style );
}
unset( $this->field['compiler']['important'] );
}
if ( ! empty( $this->field['compiler'] ) && is_array( $this->field['compiler'] ) ) {
$keys = implode( ',', $this->field['compiler'] );
$this->parent->compilerCSS .= $keys . '{' . $style . '}';
}
}
}
/**
* Unused for now.
*
* @param mixed $data CSS data.
*/
public function css_style( $data ) {}
/**
* Unused for now.
*/
public function set_defaults() {}
/**
* Unused for now.
*/
public function render() {}
/**
* Unused for now.
*/
public function enqueue() {}
/**
* Unused for now.
*/
public function always_enqueue() {}
/**
* Unused for now.
*
* @param array $field Field array.
* @param string $value Value array.
*/
public function localize( array $field, string $value = '' ) {}
}
}

View File

@@ -0,0 +1,605 @@
<?php
/**
* Redux Framework Private Extended Functions Container Class
*
* @class Redux_Functions_Ex
* @since 3.0.0
* @package Redux_Framework/Classes
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Functions_Ex', false ) ) {
/**
* Redux Functions Class
* A Class of useful functions that can/should be shared among all Redux files.
*
* @since 3.0.0
*/
class Redux_Functions_Ex {
/**
* What is this for?
*
* @var array
*/
public static $args;
/**
* Enqueue Font Awesome.
*
* @return void
*/
public static function enqueue_font_awesome() {
wp_enqueue_style(
'font-awesome',
Redux_Core::$url . 'assets/font-awesome/css/all' . Redux_Functions::is_min() . '.css',
array(),
'6.5.1'
);
wp_enqueue_style(
'font-awesome-4-shims',
Redux_Core::$url . 'assets/font-awesome/css/v4-shims' . Redux_Functions::is_min() . '.css',
array(),
'6.5.1'
);
}
/**
* Enqueue Elusive Font.
*
* @return void
*/
public static function enqueue_elusive_font() {
wp_enqueue_style(
'redux-elusive-icon',
Redux_Core::$url . 'assets/css/vendor/elusive-icons' . Redux_Functions::is_min() . '.css',
array(),
'2.0.0'
);
}
/**
* Shim to load Extendify for backward compatibility.
*
* @return void
*/
public static function load_extendify_css() {
add_action( 'enqueue_block_editor_assets', array( __CLASS__, 'block_editor_styles' ), 99 );
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'frontend_init' ), 10 );
}
/**
* Shim to enqueue Extendify CSS in the block editor.
*
* @return void
*/
public static function block_editor_styles() {
wp_enqueue_style(
'redux-editor-styles',
Redux_Core::$url . 'assets/css/extendify-utilities.css',
array(),
Redux_Core::$version
);
}
/**
* Scripts to enqueue on the frontend
*/
public static function frontend_init() {
wp_enqueue_style(
'redux-extendify-styles',
Redux_Core::$url . 'assets/css/extendify-utilities.css',
array(),
Redux_Core::$version
);
}
/**
* Output alpha data tag for Iris alpha color picker, if enabled.
*
* @param array $data Data array.
*
* @return string
*/
public static function output_alpha_data( array $data ): string {
$index = null;
extract( $data ); // phpcs:ignore WordPress.PHP.DontExtract
$value = false;
if ( isset( $field['color_alpha'] ) && $field['color_alpha'] ) {
if ( is_array( $field['color_alpha'] ) ) {
$value = $field['color_alpha'][ $index ] ?? false;
} else {
$value = $field['color_alpha'];
}
}
return 'data-alpha-enabled="' . (bool) esc_attr( $value ) . '"';
}
/**
* Parses the string into variables without the max_input_vars limitation.
*
* @param string $str String of data.
*
* @return array|false $result
* @since 3.5.7.11
* @author harunbasic
* @access private
*/
public static function parse_str( string $str ) {
if ( '' === $str ) {
return false;
}
$result = array();
$pairs = explode( '&', $str );
foreach ( $pairs as $pair ) {
// use the original parse_str() on each element.
parse_str( $pair, $params );
$k = key( $params );
if ( ! isset( $result[ $k ] ) ) {
$result += $params;
} elseif ( is_array( $result[ $k ] ) && is_array( $params[ $k ] ) ) {
$result[ $k ] = self::array_merge_recursive_distinct( $result[ $k ], $params[ $k ] );
}
}
return $result;
}
/**
* Merge arrays without converting values with duplicate keys to arrays as array_merge_recursive does.
* As seen here http://php.net/manual/en/function.array-merge-recursive.php#92195
*
* @param array $array1 array one.
* @param array $array2 array two.
*
* @return array $merged
* @since 3.5.7.11
* @author harunbasic
* @access private
*/
public static function array_merge_recursive_distinct( array $array1, array $array2 ): array {
$merged = $array1;
foreach ( $array2 as $key => $value ) {
if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
$merged[ $key ] = self::array_merge_recursive_distinct( $merged[ $key ], $value );
} elseif ( is_numeric( $key ) && isset( $merged[ $key ] ) ) {
$merged[] = $value;
} else {
$merged[ $key ] = $value;
}
}
return $merged;
}
/**
* Records calling function.
*
* @param string $opt_name Panel opt_name.
*/
public static function record_caller( string $opt_name = '' ) {
global $pagenow;
// phpcs:ignore WordPress.Security.NonceVerification
if ( ! ( 'options-general.php' === $pagenow && isset( $_GET['page'] ) && ( 'redux-framework' === $_GET['page'] || 'health-check' === $_GET['page'] ) ) ) {
return;
}
// phpcs:ignore WordPress.PHP.DevelopmentFunctions
$caller = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 )[1]['file'];
if ( ! empty( $caller ) && ! empty( $opt_name ) && class_exists( 'Redux_Core' ) ) {
if ( ! isset( Redux_Core::$callers[ $opt_name ] ) ) {
Redux_Core::$callers[ $opt_name ] = array();
}
if ( strpos( $caller, 'class-redux-' ) !== false || strpos( $caller, 'redux-core/framework.php' ) ) {
return;
}
if ( ! in_array( $caller, Redux_Core::$callers[ $opt_name ], true ) ) {
Redux_Core::$callers[ $opt_name ][] = $caller;
}
if ( ! empty( self::$args[ $opt_name ]['callers'] ) && ! in_array( $caller, self::$args[ $opt_name ]['callers'], true ) ) {
self::$args[ $opt_name ]['callers'][] = $caller;
}
}
}
/**
* Normalize path.
*
* @param string $path Path to normalize.
*
* @return string|string[]|null
*/
public static function wp_normalize_path( string $path = '' ) {
if ( function_exists( 'wp_normalize_path' ) ) {
$path = wp_normalize_path( $path );
} else {
// Shim for pre WP 3.9.
$path = str_replace( '\\', '/', $path );
$path = preg_replace( '|(?<=.)/+|', '/', $path );
if ( ':' === substr( $path, 1, 1 ) ) {
$path = ucfirst( $path );
}
}
return $path;
}
/**
* Action to add generator tag to page HEAD.
*/
public static function generator() {
add_action( 'wp_head', array( 'Redux_Functions_Ex', 'meta_tag' ) );
}
/**
* Callback for wp_head hook to add meta tag.
*/
public static function meta_tag() {
echo '<meta name="generator" content="Redux ' . esc_html( Redux_Core::$version ) . '" />';
}
/**
* Run URL through a ssl check.
*
* @param string $url URL to check.
*
* @return string
*/
public static function verify_url_protocol( string $url ): string {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
$protocol = ! empty( $_SERVER['HTTPS'] ) && 'off' !== $_SERVER['HTTPS'] || ( ! empty( $_SERVER['SERVER_PORT'] ) && 443 === $_SERVER['SERVER_PORT'] ) ? 'https://' : 'http://';
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
$new_protocol = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) . '://'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
if ( 'http://' === $protocol && $new_protocol !== $protocol && false === strpos( $url, $new_protocol ) ) {
$url = str_replace( $protocol, $new_protocol, $url );
}
}
return $url;
}
/**
* Check s.
*
* @access public
* @return bool
* @since 4.0.0
*/
public static function s(): bool {
if ( ! get_option( 'redux_p' . 'ro_lic' . 'ense_key', false ) ) { // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
$s = get_option( 'redux_p' . 'ro_l' . 'icense_status', false ); // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
if ( in_array( $s, array( 'valid', 'site_inactive' ), true ) ) {
return true;
}
}
return false;
}
/**
* Is file in theme.
*
* @param string $file File to check.
*
* @return bool
*/
public static function file_in_theme( string $file ): bool {
$file_path = self::wp_normalize_path( dirname( $file ) );
if ( strpos( $file_path, self::wp_normalize_path( get_template_directory() ) ) !== false ) {
return true;
} elseif ( strpos( $file_path, self::wp_normalize_path( get_stylesheet_directory() ) ) !== false ) {
return true;
}
return false;
}
/**
* Is Redux embedded inside a plugin?
*
* @param string $file File to check.
*
* @return array|bool
*/
public static function is_inside_plugin( string $file ) {
$file = self::wp_normalize_path( $file );
$plugin_basename = self::wp_normalize_path( plugin_basename( $file ) );
if ( self::file_in_theme( $file ) ) {
return false;
}
if ( $plugin_basename !== $file ) {
$slug = explode( '/', $plugin_basename );
$slug = $slug[0];
return array(
'slug' => $slug,
'basename' => $plugin_basename,
'path' => $file,
'url' => self::verify_url_protocol( plugins_url( $plugin_basename ) ),
'real_path' => self::wp_normalize_path( dirname( realpath( $file ) ) ),
);
}
return false;
}
/**
* Is Redux embedded in a theme?
*
* @param string $file File to check.
*
* @return array|bool
*/
public static function is_inside_theme( string $file = '' ) {
if ( ! self::file_in_theme( $file ) ) {
return false;
}
$theme_paths = array(
self::wp_normalize_path( get_template_directory() ) => get_template_directory_uri(),
// parent.
self::wp_normalize_path( get_stylesheet_directory() ) => get_stylesheet_directory_uri(),
// child.
);
$theme_paths = array_unique( $theme_paths );
$file_path = self::wp_normalize_path( $file );
$filename = explode( DIRECTORY_SEPARATOR, $file );
end( $filename );
$filename = prev( $filename );
foreach ( $theme_paths as $theme_path => $url ) {
$real_path = self::wp_normalize_path( realpath( $theme_path ) );
if ( empty( $real_path ) ) {
continue;
}
if ( strpos( $file_path, $real_path ) !== false ) {
$slug = explode( '/', $theme_path );
$slug = end( $slug );
$relative_path = explode( $slug . '/', dirname( $file_path ) );
$relative_path = $relative_path[1];
$data = array(
'slug' => $slug,
'path' => trailingslashit( trailingslashit( $theme_path ) . $relative_path ) . $filename,
'real_path' => trailingslashit( trailingslashit( $real_path ) . $relative_path ) . $filename,
'url' => self::verify_url_protocol( trailingslashit( trailingslashit( $url ) . $relative_path ) . $filename ),
'basename' => trailingslashit( $slug ) . trailingslashit( $relative_path ) . $filename,
);
$data['realpath'] = $data['real_path']; // Shim for old extensions.
if ( count( $theme_paths ) > 1 ) {
$key = array_search( $theme_path, $theme_paths, true );
if ( false !== $key ) {
unset( $theme_paths[ $key ] );
}
$theme_paths_end = end( $theme_paths );
$parent_slug_end = explode( '/', $theme_paths_end );
$parent_slug_end = end( $parent_slug_end );
$data['parent_slug'] = $parent_slug_end;
}
return $data;
}
}
return false;
}
/**
* Used to fix 3.x and 4 compatibility for extensions
*
* @param object $extension The extension parent object.
* @param string $path - Path of the file.
* @param string $ext_class - Extension class name.
* @param string $new_class_name - New dynamic class name.
* @param string $name extension name.
*
* @return object - Extended field class.
*/
public static function extension_compatibility( $extension, string $path, string $ext_class, string $new_class_name, string $name ) {
if ( empty( $new_class_name ) ) {
return null;
}
$upload_dir = ReduxFramework::$_upload_dir . '/extension_compatibility/';
if ( ! file_exists( $upload_dir . $ext_class . '.php' ) ) {
if ( ! is_dir( $upload_dir ) ) {
$extension->filesystem->mkdir( $upload_dir );
$extension->filesystem->put_contents( $upload_dir . 'index.php', '<?php // Silence is golden.' );
}
if ( ! class_exists( $ext_class ) ) {
require_once $path;
}
if ( ! file_exists( $upload_dir . $new_class_name . '.php' ) ) {
$class_file = '<?php' . PHP_EOL . PHP_EOL .
'class {{ext_class}} extends Redux_Extension_Abstract {' . PHP_EOL .
' private $c;' . PHP_EOL .
' public function __construct( $parent, $path, $ext_class ) {' . PHP_EOL .
' $this->c = $parent->extensions[\'' . $name . '\'];' . PHP_EOL .
' // Add all the params of the Abstract to this instance.' . PHP_EOL .
' foreach( get_object_vars( $this->c ) as $key => $value ) {' . PHP_EOL .
' $this->$key = $value;' . PHP_EOL .
' }' . PHP_EOL .
' parent::__construct( $parent, $path );' . PHP_EOL .
' }' . PHP_EOL .
' // fake "extends Redux_Extension_Abstract\" using magic function' . PHP_EOL .
' public function __call( $method, $args ) {' . PHP_EOL .
' return call_user_func_array( array( $this->c, $method ), $args );' . PHP_EOL .
' }' . PHP_EOL .
'}' . PHP_EOL;
$template = str_replace( '{{ext_class}}', $new_class_name, $class_file );
// phpcs:ignore Squiz.PHP.CommentedOutCode.Found
// $parent->filesystem->put_contents( $upload_dir . $new_class_name . '.php', $template );
}
if ( file_exists( $upload_dir . $new_class_name . '.php' ) ) {
if ( ! class_exists( $new_class_name ) ) {
require_once $upload_dir . $new_class_name . '.php';
}
if ( class_exists( $new_class_name ) ) {
return new $new_class_name( $extension, $path, $ext_class );
}
}
}
return null;
}
/**
* Used to merge two deep arrays.
*
* @param array $a First array to deeply merge.
* @param array $b Second array to deeply merge.
*
* @return array - Deep merge of the two arrays.
*/
public static function nested_wp_parse_args( array &$a, array $b ): array {
$result = $b;
foreach ( $a as $k => &$v ) {
if ( is_array( $v ) && isset( $result[ $k ] ) ) {
$result[ $k ] = self::nested_wp_parse_args( $v, $result[ $k ] );
} else {
$result[ $k ] = $v;
}
}
return $result;
}
/**
* AJAX callback key
*/
public static function hash_key(): string {
$key = defined( 'AUTH_KEY' ) ? AUTH_KEY : get_site_url();
$key .= defined( 'SECURE_AUTH_KEY' ) ? SECURE_AUTH_KEY : '';
return $key;
}
/**
* Register a class path to be autoloaded.
* Registers a namespace to be autoloaded from a given path, using the
* WordPress/HM-style filenames (`class-{name}.php`).
*
* @link https://engineering.hmn.md/standards/style/php/#file-naming
*
* @param string $prefix Prefix to autoload from.
* @param string $path Path to validate.
*/
public static function register_class_path( string $prefix = '', string $path = '' ) {
if ( ! class_exists( 'Redux_Autoloader' ) ) {
require_once Redux_Path::get_path( '/inc/classes/class-redux-autoloader.php' );
}
$loader = new Redux_Autoloader( $prefix, $path );
spl_autoload_register( array( $loader, 'load' ) );
}
/**
* Check if a string starts with a string.
*
* @param string $haystack Full string.
* @param string $needle String to check if it starts with.
*
* @return bool
*/
public static function string_starts_with( string $haystack, string $needle ): bool {
$length = strlen( $needle );
return substr( $haystack, 0, $length ) === $needle;
}
/**
* Check if a string ends with a string.
*
* @param string $haystack Full string.
* @param string $needle String to check if it starts with.
*
* @return bool
*/
public static function string_ends_with( string $haystack, string $needle ): bool {
$length = strlen( $needle );
if ( ! $length ) {
return true;
}
return substr( $haystack, - $length ) === $needle;
}
/**
* Determine if Extendify plugin is installed.
*
* @param string $name Plugin name.
*
* @return bool
*/
public static function is_plugin_installed( string $name ): bool {
if ( ! function_exists( 'get_plugins' ) ) {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
}
foreach ( get_plugins() as $plugin => $data ) {
if ( $data['TextDomain'] === $name ) {
return $plugin;
}
}
return false;
}
/**
* Is plugin active.
*
* @param string $name Plugin name.
*
* @return bool
*/
public static function is_plugin_active( string $name ): bool {
if ( in_array( $name . '/' . $name . '.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ), true ) ) {
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,373 @@
<?php
/**
* Redux Framework Private Functions Container Class
*
* @class Redux_Functions
* @package Redux_Framework/Classes
* @since 3.0.0
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Functions', false ) ) {
/**
* Redux Functions Class
* A Class of useful functions that can/should be shared among all Redux files.
*
* @since 3.0.0
*/
class Redux_Functions {
/**
* ReduxFramework object pointer.
*
* @var object
*/
public static $parent;
/**
* ReduxFramework shim object pointer.
*
* @var object
*/
public static $_parent; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Check for the existence of class name via an array of class names.
*
* @param array $class_names Array of class names.
*
* @return string|bool
*/
public static function class_exists_ex( array $class_names = array() ) {
foreach ( $class_names as $class_name ) {
if ( class_exists( $class_name ) ) {
return $class_name;
}
}
return false;
}
/**
* Check for the existence of file name via an array of file names.
*
* @param array $file_names Array of file names.
*
* @return string|bool
*/
public static function file_exists_ex( array $file_names = array() ) {
foreach ( $file_names as $file_name ) {
if ( file_exists( $file_name ) ) {
return $file_name;
}
}
return false;
}
/** Extract data:
* $field = field_array
* $value = field values
* $core = Redux instance
* $mode = pro field init mode */
/**
* Parse args to handle deep arrays. The WP one does not.
*
* @param array|string $args Array of args.
* @param array $defaults Defaults array.
*
* @return array
*/
public static function parse_args( $args, array $defaults ): array {
$arr = array();
if ( ! is_array( $args ) ) {
$arr[] = $args;
} else {
$arr = $args;
}
$result = $defaults;
foreach ( $arr as $k => $v ) {
if ( is_array( $v ) && isset( $result[ $k ] ) ) {
$result[ $k ] = self::parse_args( $v, $result[ $k ] );
} else {
$result[ $k ] = $v;
}
}
return $result;
}
/**
* Deprecated: Return min tag for JS and CSS files in dev_mode.
*
* @deprecated No longer using camelCase naming conventions.
*
* @return string
*/
public static function isMin(): string { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
return self::is_min();
}
/**
* Return min tag for JS and CSS files in dev_mode.
*
* @return string
*/
public static function is_min(): string {
$min = '.min';
$dev_mode = false;
$instances = Redux::all_instances();
if ( ! empty( $instances ) ) {
foreach ( $instances as $instance ) {
if ( empty( self::$parent ) ) {
self::$parent = $instance;
self::$_parent = self::$parent;
}
if ( ! empty( $instance->args['dev_mode'] ) ) {
$dev_mode = true;
self::$parent = $instance;
self::$_parent = self::$parent;
}
}
if ( $dev_mode ) {
$min = '';
}
}
return $min;
}
/**
* Parse CSS from an output/compiler array
*
* @param array $css_array CSS data.
* @param string $style CSS style.
* @param string $value CSS values.
*
* @return string CSS string
* @since 3.2.8
* @access private
*/
public static function parse_css( array $css_array = array(), string $style = '', string $value = '' ): string {
// Something wrong happened.
if ( 0 === count( $css_array ) ) {
return '';
} else {
$css = '';
$important = false;
if ( isset( $css_array['important'] ) && true === $css_array['important'] ) {
$important = '!important';
unset( $css_array['important'] );
}
foreach ( $css_array as $element => $selector ) {
// The old way.
if ( 0 === $element ) {
return self::the_old_way( $css_array, $style );
}
// New way continued.
$css_style = $element . ':' . $value . $important . ';';
$css .= $selector . '{' . $css_style . '}';
}
}
return $css;
}
/**
* Parse CSS shim.
*
* @param array $css_array CSS data.
* @param string $style CSS style.
* @param string $value CSS values.
*
* @deprecated 4.0
*
* @return string CSS string
* @since 4.0.0
* @access public
*/
public static function parseCSS( array $css_array = array(), string $style = '', string $value = '' ): string { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', __CLASS__ . '::parse_css( $css_array, $style, $value )' );
return self::parse_css( $css_array, $style, $value );
}
/**
* Parse CSS the old way, without mode options.
*
* @param array $css_array CSS data.
* @param string $style CSS style.
*
* @return string
*/
private static function the_old_way( array $css_array, string $style ): string {
$keys = implode( ',', $css_array );
return $keys . '{' . $style . '}';
}
/**
* Return s.
*
* @access public
* @since 4.0.0
* @return string
*/
public static function gs(): string {
return get_option( 're' . 'dux_p' . 'ro_lic' . 'ense_key', '' ); // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
}
/**
* Deprecated Initialized the WordPress filesystem, if it already isn't.
*
* @since 3.2.3
* @access public
* @deprecated NO longer using camelCase naming conventions.
*
* @return void
*/
public static function initWpFilesystem() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
// phpcs:ignore Squiz.Commenting.InlineComment.InvalidEndChar
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', __CLASS__ . '::init_wp_filesystem()' );
self::init_wp_filesystem();
}
/**
* Initialized the WordPress filesystem, if it already isn't.
*
* @since 3.2.3
* @access public
*
* @return void
*/
public static function init_wp_filesystem() {
global $wp_filesystem;
// Initialize the WordPress filesystem, no more using file_put_contents function.
if ( empty( $wp_filesystem ) ) {
require_once ABSPATH . '/wp-includes/pluggable.php';
require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();
}
}
/**
* TRU.
*
* @param string $string .
* @param string $opt_name .
*
* @deprecated Ad Remover extension no longer necessary.
*
* @return void
*/
public static function tru( string $string, string $opt_name ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', '' );
}
/**
* DAT.
*
* @param string $fname .
* @param string $opt_name .
*
* @deprecated Ad Remover extension no longer necessary.
*
* @return void
*/
public static function dat( string $fname, string $opt_name ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', '' );
}
/**
* BUB.
*
* @param string $fname .
* @param string $opt_name .
*
* @deprecated Ad Remover extension no longer necessary.
*
* @return void
*/
public static function bub( string $fname, string $opt_name ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', '' );
}
/**
* YO.
*
* @param string $fname .
* @param string $opt_name .
*
* @deprecated Ad Remover extension no longer necessary.
*
* @return void
*/
public static function yo( string $fname, string $opt_name ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0', '' );
}
/**
* Sanitize camelCase keys in an array, makes then snake_case.
*
* @param array $arr Array of keys.
*
* @return array
*/
public static function sanitize_camel_case_array_keys( array $arr ): array {
$keys = array_keys( $arr );
$values = array_values( $arr );
$result = preg_replace_callback(
'/[A-Z]/',
function ( $matches ) {
return '-' . Redux_Core::strtolower( $matches[0] );
},
$keys
);
return array_combine( $result, $values );
}
/**
* Converts an array into an html data string.
*
* @param array $data example input: array('id'=>'true').
*
* @return string $data_string example output: data-id='true'
*/
public static function create_data_string( array $data = array() ): string {
$data_string = '';
foreach ( $data as $key => $value ) {
if ( is_array( $value ) ) {
$value = implode( '|', $value );
}
$data_string .= ' data-' . $key . '=' . Redux_Helpers::make_bool_str( $value ) . ' ';
}
return $data_string;
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Load the plugin text domain for translation.
*
* @package Redux Framework/Classes
* @since 3.0.5
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_I18n', false ) ) {
/**
* Class Redux_I18n
*/
class Redux_I18n extends Redux_Class {
/**
* Redux_I18n constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
add_action( 'init', array( $this, 'load' ) );
}
/**
* Load translations.
*/
public function load() {
$domain = 'redux-framework';
unload_textdomain( $domain );
$core = $this->core();
/**
* Locale for text domain
* filter 'redux/textdomain/basepath/{opt_name}'
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$locale = apply_filters( 'redux/locale', get_locale(), 'redux-framework' );
$mofile = $domain . '-' . $locale . '.mo';
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$basepath = apply_filters( "redux/textdomain/basepath/{$core->args['opt_name']}", Redux_Core::$dir );
$loaded = load_textdomain( $domain, $basepath . 'languages/' . $mofile );
if ( ! $loaded ) {
$mofile = WP_LANG_DIR . '/plugins/' . $mofile;
load_textdomain( $domain, $mofile );
}
}
}
}

View File

@@ -0,0 +1,27 @@
<?php // phpcs:ignore WordPress.Files.FileName
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Installer_Muter', false ) ) {
/**
* Redux_Installer_Muter.
*
* @since 4.0.0
*/
class Redux_Installer_Muter extends WP_Upgrader_Skin {
/**
* Suppress feedback.
*
* @param string|null $feedback A string.
* @param array|null ...$args Passed args.
*
* @return void
* @since 4.0.0
*/
public function feedback( $feedback, ...$args ) {
/* no output */
}
}
}

View File

@@ -0,0 +1,120 @@
<?php
/**
* Redux Framework Instance Container Class
* Automatically captures and stores all instances
* of ReduxFramework at instantiation.
*
* @package Redux_Framework/Classes
* @subpackage Core
* @noinspection PhpIgnoredClassAliasDeclaration
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Instances', false ) ) {
/**
* Class Redux_Instances
*/
class Redux_Instances {
/**
* ReduxFramework instances
*
* @var ReduxFramework[]
*/
private static $instances;
/**
* Get Instance
* Get Redux_Instances instance
* OR an instance of ReduxFramework by [opt_name]
*
* @param string|false $opt_name the defined opt_name.
*
* @return ReduxFramework|Redux_Instances class instance
*/
public static function get_instance( $opt_name = false ) {
if ( $opt_name && ! empty( self::$instances[ $opt_name ] ) ) {
return self::$instances[ $opt_name ];
}
return new self();
}
/**
* Shim for old get_redux_instance method.
*
* @param string|false $opt_name the defined opt_name.
*
* @return ReduxFramework class instance
*/
public static function get_redux_instance( $opt_name = '' ) {
return self::get_instance( $opt_name );
}
/**
* Get all instantiated ReduxFramework instances (so far)
*
* @return array|null [type] [description]
*/
public static function get_all_instances(): ?array {
return self::$instances;
}
/**
* Redux_Instances constructor.
*
* @param mixed $redux_framework Is object.
*/
public function __construct( $redux_framework = false ) {
if ( false !== $redux_framework ) {
$this->store( $redux_framework );
} else {
add_action( 'redux/construct', array( $this, 'store' ), 5, 1 );
}
}
/**
* Action hook callback.
*
* @param object $redux_framework Pointer.
*/
public function store( $redux_framework ) {
if ( $redux_framework instanceof ReduxFramework ) {
$key = $redux_framework->args['opt_name'];
self::$instances[ $key ] = $redux_framework;
}
}
}
}
if ( ! class_exists( 'ReduxFrameworkInstances' ) ) {
class_alias( 'Redux_Instances', 'ReduxFrameworkInstances' );
}
if ( ! function_exists( 'get_redux_instance' ) ) {
/**
* Shim function that some theme oddly used.
*
* @param string|false $opt_name the defined opt_name.
*
* @return ReduxFramework class instance
*/
function get_redux_instance( $opt_name ) {
return Redux_Instances::get_instance( $opt_name );
}
}
if ( ! function_exists( 'get_all_redux_instances' ) ) {
/**
* Fetch all instances of ReduxFramework
* as an associative array.
*
* @return array format ['opt_name' => $ReduxFramework]
*/
function get_all_redux_instances(): ?array {
return Redux_Instances::get_all_instances();
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* Redux Network Class
*
* @class Redux_Network
* @version 4.0.0
* @package Redux Framework/Classes
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Network', false ) ) {
/**
* Class Redux_Network
*/
class Redux_Network extends Redux_Class {
/**
* Redux_Network constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
if ( 'network' === $redux->args['database'] && $redux->args['network_admin'] ) {
add_action(
'network_admin_edit_redux_' . $redux->args['opt_name'],
array(
$this,
'save_network_page',
),
10,
0
);
// phpcs:ignore Generic.Strings.UnnecessaryStringConcat
add_action( 'admin' . '_bar' . '_menu', array( $this, 'network_admin_bar' ), 999 );
}
}
/**
* Add node to network admin bar.
*
* @param object $wp_admin_bar Admin bar.
*/
public function network_admin_bar( $wp_admin_bar ) {
$core = $this->core();
$args = array(
'id' => $core->args['opt_name'] . '_network_admin',
'title' => $core->args['menu_title'],
'parent' => 'network-admin',
'href' => network_admin_url( 'settings.php' ) . '?page=' . $core->args['page_slug'],
'meta' => array( 'class' => 'redux-network-admin' ),
);
$wp_admin_bar->add_node( $args );
}
/**
* Saves network options.
*/
public function save_network_page() {
$core = $this->core();
if ( isset( $_POST[ $core->args['opt_name'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$opt_name = sanitize_text_field( wp_unslash( $_POST[ $core->args['opt_name'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification
}
$data = $core->options_class->validate_options( $opt_name );
if ( ! empty( $data ) ) {
$core->options_class->set( $data );
}
wp_safe_redirect(
add_query_arg(
array(
'page' => $core->args['page_slug'],
'updated' => 'true',
),
network_admin_url( 'settings.php' )
)
);
exit();
}
}
}

View File

@@ -0,0 +1,209 @@
<?php
/**
* Redux Option Defaults Class
*
* @class Redux_Options_Defaults
* @version 4.0.0
* @package Redux Framework/Classes
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Options_Defaults', false ) ) {
/**
* Class Redux_Options_Defaults
*/
class Redux_Options_Defaults {
/**
* Default options.
*
* @var array
*/
public $options_defaults = array();
/**
* Field array.
*
* @var array
*/
public $fields = array();
/**
* Is repeater group flag.
*
* @var bool
*/
private $is_repeater_group = false;
/**
* Repeater ID.
*
* @var bool
*/
private $repeater_id = '';
/**
* Creates a default options array.
*
* @param string $opt_name Panel opt_name.
* @param array $sections Panel sections array.
* @param null $wp_data_class WordPress data class.
*
* @return array
*/
public function default_values( string $opt_name = '', array $sections = array(), $wp_data_class = null ): array {
// We want it to be clean each time this is run.
$this->options_defaults = array();
// Check to make sure we're not in the select2 action, we don't want to fetch any there.
if ( isset( $_REQUEST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( Redux_Functions_Ex::string_ends_with( $action, '_select2' ) && Redux_Functions_Ex::string_starts_with( $action, 'redux_' ) ) {
return array();
}
}
if ( ! empty( $sections ) ) {
// Fill the cache.
foreach ( $sections as $sk => $section ) {
if ( ! isset( $section['id'] ) ) {
if ( ! is_numeric( $sk ) || ! isset( $section['title'] ) ) {
$section['id'] = $sk;
} else {
$section['id'] = sanitize_title( $section['title'], $sk );
}
$sections[ $sk ] = $section;
}
if ( isset( $section['fields'] ) ) {
foreach ( $section['fields'] as $field ) {
if ( empty( $field['id'] ) && empty( $field['type'] ) ) {
continue;
}
$this->field_default_values( $opt_name, $field, $wp_data_class, false );
if ( 'tabbed' === $field['type'] ) {
if ( ! empty( $field['tabs'] ) ) {
foreach ( $field['tabs'] as $val ) {
if ( ! empty( $val['fields'] ) ) {
foreach ( $val['fields'] as $f ) {
$this->field_default_values( $opt_name, $f, $wp_data_class, false, true );
}
}
}
}
}
if ( 'repeater' === $field['type'] ) {
if ( ! empty( $field['fields'] ) ) {
foreach ( $field['fields'] as $f ) {
$this->field_default_values( $opt_name, $f, $wp_data_class, true );
}
}
}
}
}
}
}
return $this->options_defaults;
}
/**
* Field default values.
*
* @param string $opt_name Panel opt_name.
* @param array $field Field array.
* @param null $wp_data_class WordPress data class.
* @param bool $is_repeater Is a repeater field.
* @param bool $is_tabbed Is a tabbed field.
*/
public function field_default_values( string $opt_name = '', array $field = array(), $wp_data_class = null, bool $is_repeater = false, $is_tabbed = false ) {
if ( 'repeater' === $field['type'] ) {
if ( isset( $field['group_values'] ) && true === $field['group_values'] ) {
$this->is_repeater_group = true;
$this->repeater_id = $field['id'];
}
}
if ( null === $wp_data_class && class_exists( 'Redux_WordPress_Data' ) && ! ( 'select' === $field['type'] && isset( $field['ajax'] ) && $field['ajax'] ) ) {
$wp_data_class = new Redux_WordPress_Data( $opt_name );
}
// Detect what field types are being used.
if ( ! isset( $this->fields[ $field['type'] ][ $field['id'] ] ) ) {
$this->fields[ $field['type'] ][ $field['id'] ] = 1;
} else {
$this->fields[ $field['type'] ] = array( $field['id'] => 1 );
}
if ( isset( $field['default'] ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$def = apply_filters( "redux/$opt_name/field/{$field['type']}/defaults", $field['default'], $field );
if ( true === $is_repeater ) {
if ( true === $this->is_repeater_group ) {
$this->options_defaults[ $this->repeater_id ][ $field['id'] ] = array( $def );
} else {
$this->options_defaults[ $field['id'] ] = array( $def );
}
} elseif ( true === $is_tabbed ) {
$this->options_defaults[ $field['id'] ] = $def;
} else {
$this->options_defaults[ $field['id'] ] = $def;
}
} elseif ( ( 'ace_editor' !== $field['type'] ) && ! ( 'select' === $field['type'] && ! empty( $field['ajax'] ) ) ) {
if ( isset( $field['data'] ) ) {
if ( ! isset( $field['args'] ) ) {
$field['args'] = array();
}
if ( is_array( $field['data'] ) && ! empty( $field['data'] ) ) {
foreach ( $field['data'] as $key => $data ) {
if ( ! empty( $data ) ) {
if ( ! isset( $field['args'][ $key ] ) ) {
$field['args'][ $key ] = array();
}
if ( null !== $wp_data_class ) {
$field['options'][ $key ] = $wp_data_class->get( $data, $field['args'][ $key ], $opt_name );
}
}
}
} elseif ( null !== $wp_data_class ) {
$field['options'] = $wp_data_class->get( $field['data'], $field['args'], $opt_name );
}
if ( 'sorter' === $field['type'] && ! empty( $field['data'] ) && is_array( $field['data'] ) ) {
if ( ! isset( $field['args'] ) ) {
$field['args'] = array();
}
foreach ( $field['data'] as $key => $data ) {
if ( ! isset( $field['args'][ $key ] ) ) {
$field['args'][ $key ] = array();
}
if ( null !== $wp_data_class ) {
$field['options'][ $key ] = $wp_data_class->get( $data, $field['args'][ $key ], $opt_name );
}
}
}
if ( isset( $field['options'] ) ) {
if ( 'sortable' === $field['type'] ) {
$this->options_defaults[ $field['id'] ] = ( true === $is_repeater ) ? array( array() ) : array();
} elseif ( 'image_select' === $field['type'] ) {
$this->options_defaults[ $field['id'] ] = ( true === $is_repeater ) ? array( '' ) : '';
} elseif ( 'select' === $field['type'] ) {
$this->options_defaults[ $field['id'] ] = ( true === $is_repeater ) ? array( '' ) : '';
} else {
$this->options_defaults[ $field['id'] ] = ( true === $is_repeater ) ? array( $field['options'] ) : $field['options'];
}
}
}
}
}
}
}

View File

@@ -0,0 +1,370 @@
<?php
/**
* Redux Output Class
*
* @class Redux_Output
* @version 3.0.0
* @package Redux Framework/Classes
* @noinspection PhpConditionCheckedByNextConditionInspection
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Output', false ) ) {
/**
* Class Redux_Output
*/
class Redux_Output extends Redux_Class {
/**
* Redux_Output constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
// Output dynamic CSS.
// Frontend: Maybe enqueue dynamic CSS and Google fonts.
if ( empty( $this->args['output_location'] ) || in_array( 'frontend', $this->args['output_location'], true ) ) {
add_action( 'wp_head', array( $this, 'output_css' ), 150 );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ), 150 );
}
// Login page: Maybe enqueue dynamic CSS and Google fonts.
if ( in_array( 'login', $this->args['output_location'], true ) ) {
add_action( 'login_head', array( $this, 'output_css' ), 150 );
add_action( 'login_enqueue_scripts', array( $this, 'enqueue' ), 150 );
}
// Admin area: Maybe enqueue dynamic CSS and Google fonts.
if ( in_array( 'admin', $this->args['output_location'], true ) ) {
add_action( 'admin_head', array( $this, 'output_css' ), 150 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ), 150 );
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/output/{$this->parent->args['opt_name']}/construct", $this );
// Useful for adding different locations for CSS output.
}
/**
* Enqueue CSS and Google fonts for front end
*
* @return void
* @throws ReflectionException Exception.
* @since 1.0.0
* @access public
*/
public function enqueue() {
$core = $this->core();
if ( false === $core->args['output'] && false === $core->args['compiler'] ) {
return;
}
foreach ( $core->sections as $k => $section ) {
if ( isset( $section['type'] ) && ( 'divide' === $section['type'] ) ) {
continue;
}
if ( isset( $section['fields'] ) ) {
foreach ( $section['fields'] as $fieldk => $field ) {
if ( isset( $field['type'] ) && 'callback' !== $field['type'] ) {
$field_classes = array( 'Redux_' . $field['type'], 'ReduxFramework_' . $field['type'] );
$field_class = Redux_Functions::class_exists_ex( $field_classes );
if ( false === $field_class ) {
if ( ! isset( $field['compiler'] ) ) {
$field['compiler'] = '';
}
$field_type = str_replace( '_', '-', $field['type'] );
$core_path = Redux_Core::$dir . "inc/fields/{$field['type']}/class-redux-$field_type.php";
if ( ! file_exists( $core_path ) ) {
$core_path = Redux_Core::$dir . "inc/fields/{$field['type']}/field_{$field['type']}.php";
}
$filter_path = $core_path;
/**
* Field class file
* filter 'redux/{opt_name}/field/class/{field.type}
*
* @param string $file field class file.
* @param array $field field config data
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$class_file = apply_filters( "redux/{$core->args['opt_name']}/field/class/{$field['type']}", $filter_path, $field );
if ( $class_file && file_exists( $class_file ) && ( ! class_exists( $field_class ) ) ) {
require_once $class_file;
$field_class = Redux_Functions::class_exists_ex( $field_classes );
}
}
$field['default'] = $field['default'] ?? '';
$value = $core->options[ $field['id'] ] ?? $field['default'];
$style_data = '';
if ( empty( $field_class ) ) {
continue;
}
$field_object = new $field_class( $field, $value, $core );
if ( ! empty( $core->options[ $field['id'] ] ) && class_exists( $field_class ) && method_exists( $field_class, 'output' ) && $this->can_output_css( $core, $field ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$field = apply_filters( "redux/field/{$core->args['opt_name']}/output_css", $field );
if ( ! empty( $field['output'] ) && ! is_array( $field['output'] ) ) {
$field['output'] = array( $field['output'] );
}
if ( ( ( isset( $field['output'] ) && ! empty( $field['output'] ) ) || ( isset( $field['compiler'] ) && ! empty( $field['compiler'] ) ) || isset( $field['media_query'] ) && ! empty( $field['media_query'] ) || 'typography' === $field['type'] || 'icon_select' === $field['type'] || 'social_profiles' === $field['type'] ) ) {
if ( method_exists( $field_class, 'css_style' ) ) {
$style_data = $field_object->css_style( $field_object->value );
}
}
if ( null !== $style_data ) {
if ( ( ( isset( $field['output'] ) && ! empty( $field['output'] ) ) || ( isset( $field['compiler'] ) && ! empty( $field['compiler'] ) ) || 'typography' === $field['type'] || 'icon_select' === $field['type'] || 'social_profiles' === $field['type'] ) ) {
$field_object->output( $style_data );
}
if ( isset( $field['media_query'] ) && ! empty( $field['media_query'] ) ) {
$field_object->media_query( $style_data );
}
}
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/field/{$core->args['opt_name']}/output_loop", $core, $field, $value, $style_data );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/field/{$core->args['opt_name']}/output_loop/{$field['type']}", $core, $field, $value, $style_data );
if ( method_exists( $field_class, 'output_variables' ) && $this->can_output_css( $core, $field ) ) {
$passed_style_data = $field_object->output_variables( $style_data );
$this->output_variables( $core, $section, $field, $value, $passed_style_data );
}
}
}
if ( ! empty( $core->outputCSS ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$core->outputCSS = html_entity_decode( $core->outputCSS, ENT_QUOTES, 'UTF-8' );
}
}
}
// For use like in the customizer. Stops the output, but passes the CSS in the variable for the compiler.
if ( isset( $core->no_output ) ) {
return;
}
if ( ! empty( $core->typography ) && filter_var( $core->args['output'], FILTER_VALIDATE_BOOLEAN ) ) {
$version = ! empty( $core->transients['last_save'] ) ? $core->transients['last_save'] : '';
if ( ! class_exists( 'Redux_Typography' ) ) {
require_once Redux_Core::$dir . '/inc/fields/typography/class-redux-typography.php';
}
$typography = new Redux_Typography( null, null, $core );
if ( ! $core->args['disable_google_fonts_link'] ) {
$url = $typography->make_google_web_font_link( $core->typography );
wp_enqueue_style( 'redux-google-fonts-' . $core->args['opt_name'], $url, array(), $version );
add_filter( 'style_loader_tag', array( $this, 'add_style_attributes' ), 10, 4 );
add_filter( 'wp_resource_hints', array( $this, 'google_fonts_preconnect' ), 10, 2 );
}
}
}
/**
* Add a Google Fonts preconnect link.
*
* @param array $urls HTML to be added.
* @param string $relationship_type Handle name.
*
* @return array
* @since 4.1.15
* @access public
*/
public function google_fonts_preconnect( array $urls, string $relationship_type ): array {
if ( 'preconnect' !== $relationship_type ) {
return $urls;
}
$urls[] = array(
'rel' => 'preconnect',
'href' => 'https://fonts.gstatic.com',
'crossorigin',
);
return $urls;
}
/**
* Filter to enhance the google fonts enqueue.
*
* @param string $html HTML to be added.
* @param string $handle Handle name.
* @param string $href HREF URL of a script.
*
* @return string
* @since 4.1.15
* @access public
*/
public function add_style_attributes( string $html = '', string $handle = '', string $href = '' ): string {
if ( Redux_Functions_Ex::string_starts_with( $handle, 'redux-google-fonts-' ) ) {
// Revamp thanks to Harry: https://csswizardry.com/2020/05/the-fastest-google-fonts/.
$href = str_replace( array( '|', ' ' ), array( '%7C', '%20' ), urldecode( $href ) );
$new_html = '<link rel="preload" as="style" href="' . esc_attr( $href ) . '" />';
$new_html .= '<link rel="stylesheet" href="' . esc_attr( $href ) . '" media="print" onload="this.media=\'all\'">'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
$new_html .= '<noscript><link rel="stylesheet" href="' . esc_attr( $href ) . '" /></noscript>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
$html = $new_html;
}
return $html;
}
/**
* Function to output output_variables to the dynamic output.
*
* @param object $core ReduxFramework core pointer.
* @param array $section Section containing this field.
* @param array $field Field object.
* @param array|string $value Current value of field.
* @param string|null $style_data CSS output string to append to the root output variable.
*
* @return void
* @since 4.0.3
* @access public
*/
private function output_variables( $core, array $section = array(), array $field = array(), $value = array(), ?string $style_data = '' ) {
// Let's allow section overrides, please.
if ( isset( $section['output_variables'] ) && ! isset( $field['output_variables'] ) ) {
$field['output_variables'] = $section['output_variables'];
}
if ( isset( $section['output_variables_prefix'] ) && ! isset( $field['output_variables_prefix'] ) ) {
$field['output_variables_prefix'] = $section['output_variables_prefix'];
}
if ( isset( $field['output_variables'] ) && $field['output_variables'] ) {
$output_variables_prefix = $core->args['output_variables_prefix'];
if ( isset( $field['output_variables_prefix'] ) && ! empty( $field['output_variables_prefix'] ) ) {
$output_variables_prefix = $field['output_variables_prefix'];
} elseif ( isset( $section['output_variables_prefix'] ) && ! empty( $section['output_variables_prefix'] ) ) {
$output_variables_prefix = $section['output_variables_prefix'];
}
if ( is_array( $value ) ) {
$val_pieces = array_filter( $value, 'strlen' );
// We don't need to show the Google boolean.
if ( 'typography' === $field['type'] && isset( $val_pieces['google'] ) ) {
unset( $val_pieces['google'] );
}
foreach ( $val_pieces as $val_key => $val_val ) {
$val_key = $output_variables_prefix . sanitize_title_with_dashes( $field['id'] ) . '-' . $val_key;
$core->output_variables[ $val_key ] = $val_val;
if ( ! empty( $style_data ) ) {
$val_key = $output_variables_prefix . sanitize_title_with_dashes( $field['id'] );
$core->output_variables[ $val_key ] = $style_data;
}
}
} else {
$val_key = $output_variables_prefix . sanitize_title_with_dashes( $field['id'] );
if ( ! empty( $style_data ) ) {
$core->output_variables[ $val_key ] = $style_data;
} else {
$core->output_variables[ $val_key ] = $value;
}
}
}
}
/**
* Output dynamic CSS at the bottom of HEAD
*
* @return void
* @since 3.2.8
* @access public
*/
public function output_css() {
$core = $this->core();
if ( false === $core->args['output'] && false === $core->args['compiler'] && empty( $core->output_variables ) ) {
return;
}
if ( isset( $core->no_output ) ) {
return;
}
if ( ! empty( $core->output_variables ) ) {
$root_css = ':root{';
foreach ( $core->output_variables as $key => $value ) {
$root_css .= "$key:$value;";
}
$root_css .= '}';
// phpcs:ignore WordPress.NamingConventions.ValidVariableName, WordPress.Security.EscapeOutput
$core->outputCSS = $root_css . $core->outputCSS;
}
// phpcs:ignore WordPress.NamingConventions.ValidVariableName
if ( ! empty( $core->outputCSS ) && ( true === $core->args['output_tag'] || ( isset( $_POST['customized'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'preview-customize_' . wp_get_theme()->get_stylesheet() ) ) ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidVariableName, WordPress.Security.EscapeOutput
echo '<style id="' . esc_attr( $core->args['opt_name'] ) . '-dynamic-css" title="dynamic-css" class="redux-options-output">' . $core->outputCSS . '</style>';
}
}
/**
* Can Output CSS
* Check if a field meets its requirements before outputting to CSS
*
* @param object $core ReduxFramework core pointer.
* @param array $field Field array.
*
* @return bool
*/
private function can_output_css( $core, array $field ): ?bool {
$return = true;
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$field = apply_filters( "redux/field/{$core->args['opt_name']}/_can_output_css", $field );
if ( isset( $field['force_output'] ) && true === $field['force_output'] ) {
return true;
}
if ( ! empty( $field['required'] ) ) {
if ( isset( $field['required'][0] ) ) {
if ( ! is_array( $field['required'][0] ) && 3 === count( $field['required'] ) ) {
$parent_value = $GLOBALS[ $core->args['global_variable'] ][ $field['required'][0] ] ?? '';
$check_value = $field['required'][2];
$operation = $field['required'][1];
$return = $core->required_class->compare_value_dependencies( $parent_value, $check_value, $operation );
} elseif ( is_array( $field['required'][0] ) ) {
foreach ( $field['required'] as $required ) {
if ( isset( $required[0] ) && ! is_array( $required[0] ) && 3 === count( $required ) ) {
$parent_value = $GLOBALS[ $core->args['global_variable'] ][ $required[0] ] ?? '';
$check_value = $required[2];
$operation = $required[1];
$return = $core->required_class->compare_value_dependencies( $parent_value, $check_value, $operation );
}
if ( ! $return ) {
return $return;
}
}
}
}
}
return $return;
}
}
}

View File

@@ -0,0 +1,431 @@
<?php
/**
* Redux Panel Class
*
* @class Redux_Panel
* @version 3.0.0
* @package Redux Framework/Classes
* @noinspection PhpIgnoredClassAliasDeclaration
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Panel', false ) ) {
/**
* Class Redux_Panel
*/
class Redux_Panel {
/**
* ReduxFramework object pointer.
*
* @var object
*/
public $parent = null;
/**
* Path to templates dir.
*
* @var null|string
*/
public $template_path = null;
/**
* Original template path.
*
* @var null
*/
public $original_path = null;
/**
* Sets the path from the arg or via filter. Also calls the panel template function.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
$this->parent = $redux;
$this->template_path = Redux_Core::$dir . 'templates/panel/';
$this->original_path = Redux_Core::$dir . 'templates/panel/';
if ( ! empty( $this->parent->args['templates_path'] ) ) {
$this->template_path = trailingslashit( $this->parent->args['templates_path'] );
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$this->template_path = trailingslashit( apply_filters( "redux/{$this->parent->args['opt_name']}/panel/templates_path", $this->template_path ) );
}
/**
* Class init.
*/
public function init() {
$this->panel_template();
}
/**
* Loads the panel templates where needed and provides the container for Redux
*/
private function panel_template() {
if ( $this->parent->args['dev_mode'] ) {
$this->template_file_check_notice();
}
/**
* Action 'redux/{opt_name}/panel/before'
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/{$this->parent->args['opt_name']}/panel/before" );
echo '<div class="wrap"><h2></h2></div>'; // Stupid hack for WordPress alerts and warnings.
echo '<div class="clear"></div>';
echo '<div class="wrap redux-wrap-div" data-opt-name="' . esc_attr( $this->parent->args['opt_name'] ) . '">';
// Do we support JS?
echo '<noscript><div class="no-js">' . esc_html__( 'Warning- This options panel will not work properly without javascript!', 'redux-framework' ) . '</div></noscript>';
// Security is vital!
echo '<input type="hidden" class="redux-ajax-security" data-opt-name="' . esc_attr( $this->parent->args['opt_name'] ) . '" id="ajaxsecurity" name="security" value="' . esc_attr( wp_create_nonce( 'redux_ajax_nonce' . $this->parent->args['opt_name'] ) ) . '" />';
/**
* Action 'redux/page/{opt_name}/form/before'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/page/{$this->parent->args['opt_name']}/form/before", $this );
if ( is_rtl() ) {
$this->parent->args['class'] = ' redux-rtl';
}
$this->get_template( 'container.tpl.php' );
/**
* Action 'redux/page/{opt_name}/form/after'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/page/{$this->parent->args['opt_name']}/form/after", $this );
echo '<div class="clear"></div>';
echo '</div>';
if ( true === $this->parent->args['dev_mode'] ) {
echo '<br /><div class="redux-timer">' . esc_html( get_num_queries() ) . ' queries in ' . esc_html( timer_stop() ) . ' seconds<br/>Redux is currently set to developer mode.</div>';
}
/**
* Action 'redux/{opt_name}/panel/after'
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/{$this->parent->args['opt_name']}/panel/after" );
}
/**
* Calls the various notification bars and sets the appropriate templates.
*/
public function notification_bar() {
if ( isset( $this->parent->transients['last_save_mode'] ) ) {
if ( 'import' === $this->parent->transients['last_save_mode'] ) {
/**
* Action 'redux/options/{opt_name}/import'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/import", $this, $this->parent->transients['changed_values'] );
echo '<div class="admin-notice notice-blue saved_notice">';
/**
* Filter 'redux-imported-text-{opt_name}'
*
* @param string $text Translated "settings imported" text.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo '<strong>' . esc_html( apply_filters( "redux-imported-text-{$this->parent->args['opt_name']}", esc_html__( 'Settings Imported!', 'redux-framework' ) ) ) . '</strong>';
echo '</div>';
} elseif ( 'defaults' === $this->parent->transients['last_save_mode'] ) {
/**
* Action 'redux/options/{opt_name}/reset'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/reset", $this );
echo '<div class="saved_notice admin-notice notice-yellow">';
/**
* Filter 'redux-defaults-text-{opt_name}'
*
* @param string $text Translated "settings imported" text.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo '<strong>' . esc_html( apply_filters( "redux-defaults-text-{$this->parent->args['opt_name']}", esc_html__( 'All Defaults Restored!', 'redux-framework' ) ) ) . '</strong>';
echo '</div>';
} elseif ( 'defaults_section' === $this->parent->transients['last_save_mode'] ) {
/**
* Action 'redux/options/{opt_name}/section/reset'
*
* @param object $this ReduxFramework
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/section/reset", $this );
echo '<div class="saved_notice admin-notice notice-yellow">';
/**
* Filter 'redux-defaults-section-text-{opt_name}'
*
* @param string $text Translated "settings imported" text.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo '<strong>' . esc_html( apply_filters( "redux-defaults-section-text-{$this->parent->args['opt_name']}", esc_html__( 'Section Defaults Restored!', 'redux-framework' ) ) ) . '</strong>';
echo '</div>';
} elseif ( 'normal' === $this->parent->transients['last_save_mode'] ) {
/**
* Action 'redux/options/{opt_name}/saved'
*
* @param mixed $value set/saved option value
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/saved", $this->parent->options, $this->parent->transients['changed_values'] );
echo '<div class="saved_notice admin-notice notice-green">';
/**
* Filter 'redux-saved-text-{opt_name}'
*
* @param string $text Translated "settings saved" text.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo '<strong>' . esc_html( apply_filters( "redux-saved-text-{$this->parent->args['opt_name']}", esc_html__( 'Settings Saved!', 'redux-framework' ) ) ) . '</strong>';
echo '</div>';
}
unset( $this->parent->transients['last_save_mode'] );
$this->parent->transient_class->set();
}
/**
* Action 'redux/options/{opt_name}/settings/changes'
*
* @param mixed $value set/saved option value
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/settings/change", $this->parent->options, $this->parent->transients['changed_values'] );
echo '<div class="redux-save-warn notice-yellow">';
/**
* Filter 'redux-changed-text-{opt_name}'
*
* @param string $text Translated "settings have changed" text.
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
echo '<strong>' . esc_html( apply_filters( "redux-changed-text-{$this->parent->args['opt_name']}", esc_html__( 'Settings have changed, you should save them!', 'redux-framework' ) ) ) . '</strong>';
echo '</div>';
/**
* Action 'redux/options/{opt_name}/errors'
*
* @param array $this ->errors error information
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/errors", $this->parent->errors );
echo '<div class="redux-field-errors notice-red">';
echo '<strong>';
echo '<span></span> ' . esc_html__( 'error(s) were found!', 'redux-framework' );
echo '</strong>';
echo '</div>';
/**
* Action 'redux/options/{opt_name}/warnings'
*
* @param array $this ->warnings warning information
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/options/{$this->parent->args['opt_name']}/warnings", $this->parent->warnings );
echo '<div class="redux-field-warnings notice-yellow">';
echo '<strong>';
echo '<span></span> ' . esc_html__( 'warning(s) were found!', 'redux-framework' );
echo '</strong>';
echo '</div>';
}
/**
* Used to initialize the settings fields for this panel. Required for saving and redirect.
*/
private function init_settings_fields() {
// Must run or the page won't redirect properly.
settings_fields( "{$this->parent->args['opt_name']}_group" );
}
/**
* Enable file deprecate warning from core. This is necessary because the function is considered private.
*
* @return bool
*/
public function tick_file_deprecate_warning(): bool {
return true;
}
/**
* Used to select the proper template. If it doesn't exist in the path, then the original template file is used.
*
* @param string $file Path to template file.
*/
public function get_template( string $file ) {
if ( empty( $file ) ) {
return;
}
if ( file_exists( $this->template_path . $file ) ) {
$path = $this->template_path . $file;
} else {
$path = $this->original_path . $file;
}
// Shim for v3 templates.
if ( ! file_exists( $path ) ) {
$old_file = $file;
add_filter( 'deprecated_file_trigger_error', array( $this, 'tick_file_deprecate_warning' ) );
$file = str_replace( '_', '-', $file );
_deprecated_file( esc_html( $old_file ), '4.0', esc_html( $file ), 'Please replace this outdated template with the current one from the Redux core.' );
if ( file_exists( $this->template_path . $file ) ) {
$path = $this->template_path . $file;
} else {
$path = $this->original_path . $file;
}
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/{$this->parent->args['opt_name']}/panel/template/" . $file . '/before' );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$path = apply_filters( "redux/{$this->parent->args['opt_name']}/panel/template/" . $file, $path );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/{$this->parent->args['opt_name']}/panel/template/" . $file . '/after' );
if ( file_exists( $path ) ) {
if ( is_readable( $path ) ) {
require $path;
} else {
// translators: %1$s: template path.
echo '<div class="error"><p>' . sprintf( esc_html__( 'Redux Panel Template %1$s cannot be read. Please check the permissions for this file.', 'redux-framework' ), '<code>' . esc_html( $path ) . '</code>' ) . '</p></div>';
}
} elseif ( file_exists( Redux_Core::$dir . 'templates/panel/' . $file ) ) {
require Redux_Core::$dir . 'templates/panel/' . $file;
} else {
// translators: %1$s: template path.
echo '<div class="error"><p>' . sprintf( esc_html__( 'Redux Panel Template %1$s does not exist. Please reinstall Redux to replace this file.', 'redux-framework' ), '<code>' . esc_html( $path ) . '</code>' ) . '</p></div>';
}
}
/**
* Scan the template files.
*
* @param string $template_path Path to template file.
*
* @return array
*/
public function scan_template_files( string $template_path ): array {
$files = scandir( $template_path );
$result = array();
if ( $files ) {
foreach ( $files as $value ) {
if ( ! in_array( $value, array( '.', '..' ), true ) ) {
if ( is_dir( $template_path . DIRECTORY_SEPARATOR . $value ) ) {
$sub_files = self::scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
foreach ( $sub_files as $sub_file ) {
$result[] = $value . DIRECTORY_SEPARATOR . $sub_file;
}
} else {
$result[] = $value;
}
}
}
}
return $result;
}
/**
* Show a notice highlighting bad template files
*/
public function template_file_check_notice() {
if ( $this->original_path === $this->template_path ) {
return;
}
$core_templates = $this->scan_template_files( $this->original_path );
foreach ( $core_templates as $file ) {
$developer_theme_file = false;
if ( file_exists( $this->template_path . $file ) ) {
$developer_theme_file = $this->template_path . $file;
}
if ( $developer_theme_file ) {
$core_version = Redux_Helpers::get_template_version( $this->original_path . $file );
$developer_version = Redux_Helpers::get_template_version( $developer_theme_file );
if ( $core_version && $developer_version && version_compare( $developer_version, $core_version, '<' ) ) {
?>
<div id="message" class="error redux-message" style="display:block!important">
<p>
<strong><?php esc_html_e( 'Your panel has bundled copies of Redux Framework template files that are outdated!', 'redux-framework' ); ?></strong>&nbsp;&nbsp;<?php esc_html_e( 'Please ask the author of this theme to update them as functionality issues could arise.', 'redux-framework' ); ?>
</p>
</div>
<?php
return;
}
}
}
}
/**
* Outputs the HTML for a given section using the WordPress settings API.
*
* @param mixed $k Section number of settings panel to display.
*/
private function output_section( $k ) {
do_settings_sections( $this->parent->args['opt_name'] . $k . '_section_group' );
}
}
}
if ( ! class_exists( 'reduxCorePanel' ) ) {
class_alias( 'Redux_Panel', 'reduxCorePanel' );
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Redux Path Class
*
* @class Redux_Path
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Path', false ) ) {
/**
* Class Redux_Path
*/
class Redux_Path {
/**
* Class init
*/
public static function init() {}
/**
* Gets Redux path.
*
* @param string $relative_path Self-explanatory.
*
* @return string
*/
public static function get_path( string $relative_path ): string {
return Redux_Core::$redux_path . $relative_path;
}
}
Redux_Path::init();
}

View File

@@ -0,0 +1,296 @@
<?php
/**
* Redux Required Class
*
* @class Redux_Required
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Required', false ) ) {
/**
* Class Redux_Required
*/
class Redux_Required extends Redux_Class {
/**
* Array of fields to reload.
*
* @var array
*/
public $reload_fields = array();
/**
* Redux_Required Constructor.
*
* @param object $parent ReduxFramework object.
*/
public function __construct( $parent = null ) {
parent::__construct( $parent );
}
/**
* Checks dependencies between objects based on the $field['required'] array
* If the array is set it needs to have exactly 3 entries.
* The first entry describes which field should be monitored by the current field. e.g.: "content"
* The second entry describes the comparison parameter. eg: "equals, not, is_larger, is_smaller, contains"
* The third entry describes the value that we are comparing against.
* Example: if the required array is set to array('content','equals','Hello World'); then the current
* field will only be displayed if the field with id "content" has exactly the value "Hello World"
*
* @param array $field Field array.
*/
public function check_dependencies( array $field ) {
$core = $this->core();
if ( isset( $field['ajax_save'] ) && false === $field['ajax_save'] ) {
$core->required_class->reload_fields[] = $field['id'];
}
if ( ! empty( $field['required'] ) ) {
if ( ! isset( $core->required_child[ $field['id'] ] ) ) {
$core->required_child[ $field['id'] ] = array();
}
if ( ! isset( $core->required[ $field['id'] ] ) ) {
$core->required[ $field['id'] ] = array();
}
if ( is_array( $field['required'][0] ) ) {
foreach ( $field['required'] as $value ) {
if ( is_array( $value ) && 3 === count( $value ) ) {
$data = array();
$data['parent'] = $value[0];
$data['operation'] = $value[1];
$data['checkValue'] = $value[2];
$core->required[ $data['parent'] ][ $field['id'] ][] = $data;
if ( ! in_array( $data['parent'], $core->required_child[ $field['id'] ], true ) ) {
$core->required_child[ $field['id'] ][] = $data;
}
$this->check_required_dependencies( $core, $field, $data );
}
}
} else {
$data = array();
$data['parent'] = $field['required'][0];
$data['operation'] = $field['required'][1];
$data['checkValue'] = $field['required'][2];
$core->required[ $data['parent'] ][ $field['id'] ][] = $data;
if ( false === array_search( $data['parent'], array_column( $core->required_child[ $field['id'] ], 'parent' ), true ) ) {
$core->required_child[ $field['id'] ][] = $data;
}
$this->check_required_dependencies( $core, $field, $data );
}
}
}
/**
* Check field for required deps.
*
* @param object $core ReduxFramework core pointer.
* @param array $field Field array.
* @param array $data Required data.
*/
private function check_required_dependencies( $core, array $field, array $data ) {
// The Required field must not be hidden. Otherwise, hide this one by default.
if ( ! in_array( $data['parent'], $core->fields_hidden, true ) && ( ! isset( $core->folds[ $field['id'] ] ) || 'hide' !== $core->folds[ $field['id'] ] ) ) {
if ( isset( $core->options[ $data['parent'] ] ) ) {
$return = $this->compare_value_dependencies( $core->options[ $data['parent'] ], $data['checkValue'], $data['operation'] );
} elseif ( isset( $core->options_defaults[ $data['parent'] ] ) ) {
$return = $this->compare_value_dependencies( $core->options_defaults[ $data['parent'] ], $data['checkValue'], $data['operation'] );
}
}
if ( ( isset( $return ) && $return ) && ( ! isset( $core->folds[ $field['id'] ] ) || 'hide' !== $core->folds[ $field['id'] ] ) ) {
$core->folds[ $field['id'] ] = 'show';
} else {
$core->folds[ $field['id'] ] = 'hide';
if ( ! in_array( $field['id'], $core->fields_hidden, true ) ) {
$core->fields_hidden[] = $field['id'];
}
}
}
/**
* Compare data for required field.
*
* @param mixed $parent_value Parent value.
* @param mixed $check_value Check value.
* @param string $operation Operation.
*
* @return bool
*/
public function compare_value_dependencies( $parent_value, $check_value, string $operation ): bool {
$return = false;
switch ( $operation ) {
case '=':
case 'equals':
$data['operation'] = '=';
if ( is_array( $parent_value ) ) {
foreach ( $parent_value as $val ) {
if ( is_array( $check_value ) ) {
foreach ( $check_value as $v ) {
if ( Redux_Helpers::make_bool_str( $val ) === Redux_Helpers::make_bool_str( $v ) ) {
$return = true;
}
}
} else {
if ( Redux_Helpers::make_bool_str( $val ) === Redux_Helpers::make_bool_str( $check_value ) ) {
$return = true;
}
}
}
} else {
if ( is_array( $check_value ) ) {
foreach ( $check_value as $v ) {
if ( Redux_Helpers::make_bool_str( $parent_value ) === Redux_Helpers::make_bool_str( $v ) ) {
$return = true;
}
}
} else {
if ( Redux_Helpers::make_bool_str( $parent_value ) === Redux_Helpers::make_bool_str( $check_value ) ) {
$return = true;
}
}
}
break;
case '!=':
case 'not':
$data['operation'] = '!==';
if ( is_array( $parent_value ) ) {
foreach ( $parent_value as $val ) {
if ( is_array( $check_value ) ) {
foreach ( $check_value as $v ) {
if ( Redux_Helpers::make_bool_str( $val ) !== Redux_Helpers::make_bool_str( $v ) ) {
$return = true;
}
}
} else {
if ( Redux_Helpers::make_bool_str( $val ) !== Redux_Helpers::make_bool_str( $check_value ) ) {
$return = true;
}
}
}
} else {
if ( is_array( $check_value ) ) {
foreach ( $check_value as $v ) {
if ( Redux_Helpers::make_bool_str( $parent_value ) !== Redux_Helpers::make_bool_str( $v ) ) {
$return = true;
}
}
} else {
if ( Redux_Helpers::make_bool_str( $parent_value ) !== Redux_Helpers::make_bool_str( $check_value ) ) {
$return = true;
}
}
}
break;
case '>':
case 'greater':
case 'is_larger':
$data['operation'] = '>';
if ( $parent_value > $check_value ) {
$return = true;
}
break;
case '>=':
case 'greater_equal':
case 'is_larger_equal':
$data['operation'] = '>=';
if ( $parent_value >= $check_value ) {
$return = true;
}
break;
case '<':
case 'less':
case 'is_smaller':
$data['operation'] = '<';
if ( $parent_value < $check_value ) {
$return = true;
}
break;
case '<=':
case 'less_equal':
case 'is_smaller_equal':
$data['operation'] = '<=';
if ( $parent_value <= $check_value ) {
$return = true;
}
break;
case 'contains':
if ( is_array( $parent_value ) ) {
$parent_value = implode( ',', $parent_value );
}
if ( is_array( $check_value ) ) {
foreach ( $check_value as $opt ) {
if ( strpos( $parent_value, (string) $opt ) !== false ) {
$return = true;
}
}
} elseif ( strpos( $parent_value, (string) $check_value ) !== false ) {
$return = true;
}
break;
case 'doesnt_contain':
case 'not_contain':
if ( is_array( $parent_value ) ) {
$parent_value = implode( ',', $parent_value );
}
if ( is_array( $check_value ) ) {
foreach ( $check_value as $opt ) {
if ( strpos( $parent_value, (string) $opt ) === false ) {
$return = true;
}
}
} elseif ( strpos( $parent_value, (string) $check_value ) === false ) {
$return = true;
}
break;
case 'is_empty_or':
if ( empty( $parent_value ) || $check_value === $parent_value ) {
$return = true;
}
break;
case 'not_empty_and':
if ( ! empty( $parent_value ) && $check_value !== $parent_value ) {
$return = true;
}
break;
case 'is_empty':
case 'empty':
case '!isset':
if ( empty( $parent_value ) ) {
$return = true;
}
break;
case 'not_empty':
case '!empty':
case 'isset':
if ( ! empty( $parent_value ) && '' !== $parent_value ) {
$return = true;
}
break;
}
return $return;
}
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* Redux Sanitize Class
*
* @class Redux_Sanitize
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Sanitize', false ) ) {
/**
* Class Redux_Sanitize
*/
class Redux_Sanitize extends Redux_Class {
/**
* Sanitize values from options form (used in settings api validate function)
*
* @since 4.0.0
* @access public
*
* @param array $plugin_options Plugin Options.
* @param array $options Options.
* @param array $sections Sections array.
*
* @return array $plugin_options
*/
public function sanitize( array $plugin_options, array $options, array $sections ): array {
$core = $this->core();
foreach ( $sections as $k => $section ) {
if ( isset( $section['fields'] ) ) {
foreach ( $section['fields'] as $field ) {
if ( is_array( $field ) ) {
$field['section_id'] = $k;
}
if ( isset( $field['type'] ) && ( 'text' === $field['type'] || 'textarea' === $field['type'] || 'multi_text' === $field['type'] ) ) {
// Make sure 'sanitize' field is set.
if ( isset( $field['sanitize'] ) ) {
// Can we make this an array of validations?
$val_arr = array();
if ( is_array( $field['sanitize'] ) ) {
$val_arr = $field['sanitize'];
} else {
$val_arr[] = $field['sanitize'];
}
foreach ( $val_arr as $function ) {
// Check for empty id value.
if ( ! isset( $field['id'] ) || ! isset( $plugin_options[ $field['id'] ] ) || ( '' === $plugin_options[ $field['id'] ] ) ) {
continue;
}
if ( function_exists( $function ) ) {
if ( empty( $options[ $field['id'] ] ) ) {
$options[ $field['id'] ] = '';
}
if ( is_array( $plugin_options[ $field['id'] ] ) && ! empty( $plugin_options[ $field['id'] ] ) ) {
foreach ( $plugin_options[ $field['id'] ] as $key => $value ) {
$before = null;
$after = null;
if ( isset( $plugin_options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || '0' === $plugin_options[ $field['id'] ][ $key ] ) ) {
if ( is_array( $plugin_options[ $field['id'] ][ $key ] ) ) {
$before = $plugin_options[ $field['id'] ][ $key ];
} else {
$before = trim( $plugin_options[ $field['id'] ][ $key ] );
}
}
if ( isset( $options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || '0' === $plugin_options[ $field['id'] ][ $key ] ) ) {
$after = $options[ $field['id'] ][ $key ];
}
$value = call_user_func( $function, $before );
if ( false !== $value ) {
$plugin_options[ $field['id'] ][ $key ] = $value;
} else {
unset( $plugin_options[ $field['id'] ][ $key ] );
}
$field['current'] = $value;
$core->sanitize[] = $field;
}
} else {
if ( isset( $plugin_options[ $field['id'] ] ) ) {
if ( is_array( $plugin_options[ $field['id'] ] ) ) {
$pofi = $plugin_options[ $field['id'] ];
} else {
$pofi = trim( $plugin_options[ $field['id'] ] );
}
} else {
$pofi = null;
}
$value = call_user_func( $function, $pofi );
$plugin_options[ $field['id'] ] = $value;
$field['current'] = $value;
$core->sanitize[] = $field;
}
break;
}
}
}
}
}
}
}
return $plugin_options;
}
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Redux ThirdParty Fixes Class
*
* @class Redux_ThirdParty_Fixes
* @version 3.0.0
* @package Redux Framework/Classes
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_ThirdParty_Fixes', false ) ) {
/**
* Class Redux_ThirdParty_Fixes
*/
class Redux_ThirdParty_Fixes extends Redux_Class {
/**
* Redux_ThirdParty_Fixes constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux );
$this->gt3_page_builder();
// These are necessary to override an outdated extension embedded in themes
// that are loaded via the antiquated 'loader.php' method.
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/repeater', array( $this, 'repeater_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/metaboxes', array( $this, 'metaboxes_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/social_profiles', array( $this, 'social_profiles_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/widget_areas', array( $this, 'widget_areas_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/custom_fonts', array( $this, 'custom_fonts_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/icon_select', array( $this, 'icon_select_extension_override' ) );
add_filter( 'redux/extension/' . $this->parent->args['opt_name'] . '/color_scheme', array( $this, 'color_scheme_extension_override' ) );
}
/**
* Color Scheme extension override.
*
* @return string
*/
public function color_scheme_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/color_scheme/class-redux-extension-color-scheme.php';
}
/**
* Icon Select extension override.
*
* @return string
*/
public function icon_select_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/icon_select/class-redux-extension-icon-select.php';
}
/**
* Widget Area extension override.
*
* @return string
*/
public function custom_fonts_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/custom_fonts/class-redux-extension-custom-fonts.php';
}
/**
* Widget Area extension override.
*
* @return string
*/
public function widget_areas_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/widget_areas/class-redux-extension-widget-areas.php';
}
/**
* Repeater extension override.
*
* @return string
*/
public function repeater_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/repeater/class-redux-extension-repeater.php';
}
/**
* Metaboxes extension override.
*
* @return string
*/
public function metaboxes_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/metaboxes/class-redux-extension-metaboxes.php';
}
/**
* Social Profiles extension override.
*
* @return string
*/
public function social_profiles_extension_override(): string {
return Redux_core::$dir . 'inc/extensions/social_profiles/class-redux-extension-social-profiles.php';
}
/**
* GT3 Page Builder fix.
*/
private function gt3_page_builder() {
// Fix for the GT3 page builder: http://www.gt3themes.com/wordpress-gt3-page-builder-plugin/.
if ( has_action( 'ecpt_field_options_' ) ) {
global $pagenow;
if ( 'admin.php' === $pagenow ) {
remove_action( 'admin_init', 'pb_admin_init' );
}
}
}
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Redux Transients Class
*
* @class Redux_Transients
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Transients', false ) ) {
/**
* Class Redux_Transients
*/
class Redux_Transients extends Redux_Class {
/**
* Get transients from database.
*/
public function get() {
$core = $this->core();
if ( empty( $core->transients ) ) {
$core->transients = get_option( $core->args['opt_name'] . '-transients', array() );
}
}
/**
* Set transients in database.
*/
public function set() {
$core = $this->core();
if ( ! isset( $core->transients ) || ! isset( $core->transients_check ) || $core->transients_check !== $core->transients ) {
update_option( $core->args['opt_name'] . '-transients', $core->transients );
}
}
}
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* Redux Validate Class
*
* @class Redux_Validate
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Validate', false ) ) {
/**
* Class Redux_Validate
*/
abstract class Redux_Validate {
/**
* ReduxFramework object.
*
* @var object
*/
public $parent;
/**
* Redux fields array.
*
* @var array
*/
public $field = array();
/**
* Redux values array|string.
*
* @var array|string
*/
public $value;
/**
* Validation current value.
*
* @var mixed
*/
public $current;
/**
* Warning array.
*
* @var array
*/
public $warning = array();
/**
* Error array.
*
* @var array
*/
public $error = array();
/**
* Sanitize array.
*
* @var array
*/
public $sanitize = array();
/**
* Redux_Validate constructor.
*
* @param object $redux ReduxFramework pointer.
* @param array $field Fields array.
* @param array|string $value Values array.
* @param mixed $current Current.
*/
public function __construct( $redux, array $field, $value, $current ) {
$this->parent = $redux;
$this->field = $field;
$this->value = $value;
$this->current = $current;
if ( isset( $this->field['validate_msg'] ) ) {
$this->field['msg'] = $this->field['validate_msg'];
unset( $this->field['validate_msg'] );
}
$this->validate();
}
/**
* Validate.
*
* @return mixed
*/
abstract public function validate();
}
}

View File

@@ -0,0 +1,247 @@
<?php
/**
* Redux Validation Class
*
* @class Redux_Validation
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Validation', false ) ) {
/**
* Class Redux_Validation
*/
class Redux_Validation extends Redux_Class {
/**
* Validate values from options form (used in settings api validate function)
* calls the custom validation class for the field so authors can override with custom classes
*
* @since 1.0.0
* @access public
*
* @param array $plugin_options Plugin Options.
* @param array $options Options.
* @param array $sections Sections array.
*
* @return array $plugin_options
*/
public function validate( array $plugin_options, array $options, array $sections ): array {
$core = $this->core();
foreach ( $sections as $k => $section ) {
if ( isset( $section['fields'] ) ) {
foreach ( $section['fields'] as $fkey => $field ) {
if ( is_array( $field ) ) {
$field['section_id'] = $k;
}
if ( isset( $field['type'] ) && ( 'checkbox' === $field['type'] || 'checkbox_hide_below' === $field['type'] || 'checkbox_hide_all' === $field['type'] ) ) {
if ( ! isset( $plugin_options[ $field['id'] ] ) ) {
$plugin_options[ $field['id'] ] = 0;
}
}
// Part of Dovy's serialize typography effort. Preserved here in case it becomes a thing. - kp.
/**
* If ( isset ( $field['type'] ) && $field['type'] == 'typography' ) {
* if ( ! is_array( $plugin_options[ $field['id'] ] ) && ! empty( $plugin_options[ $field['id'] ] ) ) {
* $plugin_options[ $field['id'] ] = json_decode( $plugin_options[ $field['id'] ], true );
* }
* }
*/
if ( isset( $core->extensions[ $field['type'] ] ) && method_exists( $core->extensions[ $field['type'] ], '_validate_values' ) ) {
$plugin_options = $core->extensions[ $field['type'] ]->_validate_values( $plugin_options, $field, $sections );
}
// Make sure 'validate' field is set.
if ( isset( $field['validate'] ) ) {
// Can we make this an array of validations?
$val_arr = array();
if ( is_array( $field['validate'] ) ) {
$val_arr = $field['validate'];
} else {
$val_arr[] = $field['validate'];
}
foreach ( $val_arr as $idx => $val ) {
// shim for old *_not_empty validations.
if ( 'email_not_empty' === $val || 'numeric_not_empty' === $val ) {
$val = 'not_empty';
}
// Make sure 'validate field' is set to 'not_empty'.
$is_not_empty = false;
if ( 'not_empty' === $val ) {
// Set the flag.
$is_not_empty = true;
}
// Check for empty id value.
if ( ! isset( $field['id'] ) || ! isset( $plugin_options[ $field['id'] ] ) || ( '' === $plugin_options[ $field['id'] ] ) ) {
// If we are looking for an empty value, in the case of 'not_empty'
// then we need to keep processing.
if ( ! $is_not_empty ) {
// Empty id and not checking for 'not_empty'. Bail out...
if ( ! isset( $field['validate_callback'] ) ) {
continue;
}
}
}
// Force validate of custom field types.
if ( isset( $field['type'] ) && ! isset( $val ) && ! isset( $field['validate_callback'] ) ) {
if ( 'color' === $field['type'] || 'color_gradient' === $field['type'] ) {
$val = 'color';
} elseif ( 'date' === $field['type'] ) {
$val = 'date';
}
}
// No need. Spectrum self validates.
if ( 'color_rgba' === $field['type'] ) {
continue;
}
// Shim out old color rgba validators.
if ( 'color_rgba' === $val || 'colorrgba' === $val ) {
$val = 'color';
}
$validate = 'Redux_Validation_' . $val;
if ( ! class_exists( $validate ) ) {
$file = str_replace( '_', '-', $val );
/**
* Filter 'redux/validate/{opt_name}/class/{field.validate}'
*
* @param string $validate validation class file path
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$class_file = apply_filters( "redux/validate/{$core->args['opt_name']}/class/$val", Redux_Core::$dir . "inc/validation/$val/class-redux-validation-$file.php", $validate );
if ( $class_file ) {
if ( file_exists( $class_file ) ) {
require_once $class_file;
}
}
}
if ( class_exists( $validate ) ) {
if ( empty( $options[ $field['id'] ] ) ) {
$options[ $field['id'] ] = '';
}
if ( isset( $plugin_options[ $field['id'] ] ) && is_array( $plugin_options[ $field['id'] ] ) && ! empty( $plugin_options[ $field['id'] ] ) ) {
foreach ( $plugin_options[ $field['id'] ] as $key => $value ) {
$before = null;
$after = null;
if ( isset( $plugin_options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || '0' === $plugin_options[ $field['id'] ][ $key ] ) ) {
if ( is_array( $plugin_options[ $field['id'] ][ $key ] ) ) {
$before = $plugin_options[ $field['id'] ][ $key ];
} else {
$before = trim( $plugin_options[ $field['id'] ][ $key ] );
}
}
if ( isset( $options[ $field['id'] ][ $key ] ) && ( ! empty( $plugin_options[ $field['id'] ][ $key ] ) || '0' === $plugin_options[ $field['id'] ][ $key ] ) ) {
$after = $options[ $field['id'] ][ $key ];
}
$validation = new $validate( $core, $field, $before, $after );
if ( ! empty( $validation->value ) || '0' === $validation->value ) {
$plugin_options[ $field['id'] ][ $key ] = $validation->value;
} else {
unset( $plugin_options[ $field['id'] ][ $key ] );
}
if ( ! empty( $validation->error ) ) {
$core->errors[] = $validation->error;
}
if ( ! empty( $validation->warning ) ) {
$core->warnings[] = $validation->warning;
}
if ( ! empty( $validation->sanitize ) ) {
$core->sanitize[] = $validation->sanitize;
}
}
} else {
if ( isset( $plugin_options[ $field['id'] ] ) ) {
if ( is_array( $plugin_options[ $field['id'] ] ) ) {
$pofi = $plugin_options[ $field['id'] ];
} else {
$pofi = trim( $plugin_options[ $field['id'] ] );
}
} else {
$pofi = null;
}
$validation = new $validate( $core, $field, $pofi, $options[ $field['id'] ] );
$plugin_options[ $field['id'] ] = $validation->value;
if ( ! empty( $validation->error ) ) {
$core->errors[] = $validation->error;
}
if ( ! empty( $validation->warning ) ) {
$core->warnings[] = $validation->warning;
}
if ( ! empty( $validation->sanitize ) ) {
$core->sanitize[] = $validation->sanitize;
}
}
break;
}
}
}
if ( isset( $field['validate_callback'] ) && ( is_callable( $field['validate_callback'] ) || ( is_string( $field['validate_callback'] ) && function_exists( $field['validate_callback'] ) ) ) ) {
$callback = $field['validate_callback'];
unset( $field['validate_callback'] );
$plugin_option = $plugin_options[ $field['id'] ] ?? null;
$option = $options[ $field['id'] ] ?? null;
if ( null !== $plugin_option ) {
$callbackvalues = call_user_func( $callback, $field, $plugin_option, $option );
$plugin_options[ $field['id'] ] = $callbackvalues['value'];
if ( isset( $callbackvalues['error'] ) ) {
$core->errors[] = $callbackvalues['error'];
}
if ( isset( $callbackvalues['warning'] ) ) {
$core->warnings[] = $callbackvalues['warning'];
}
if ( isset( $callbackvalues['sanitize'] ) ) {
$core->sanitize[] = $callbackvalues['sanitize'];
}
}
}
}
}
}
return $plugin_options;
}
}
}

View File

@@ -0,0 +1,683 @@
<?php
/**
* Redux WordPress Data Class
*
* @class Redux_WordPress_Data
* @version 3.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_WordPress_Data', false ) ) {
/**
* Class Redux_WordPress_Data
*/
class Redux_WordPress_Data extends Redux_Class {
/**
* Holds WordPress data.
*
* @var null
*/
private $wp_data = null;
/**
* Redux_WordPress_Data constructor.
*
* @param mixed $redux ReduxFramework pointer or opt_name.
*/
public function __construct( $redux = null ) {
if ( is_string( $redux ) ) {
$this->opt_name = $redux;
} else {
parent::__construct( $redux );
}
}
/**
* Get the data.
*
* @param string|array $type Type.
* @param array|string $args Args.
* @param string $opt_name Opt name.
* @param string|int $current_value Current value.
* @param bool $ajax Tells if this is an AJAX call.
*
* @return array|mixed|string
*/
public function get( $type, $args = array(), string $opt_name = '', $current_value = '', bool $ajax = false ) {
$opt_name = $this->opt_name;
// We don't want to run this, it's not a string value. Send it back!
if ( is_array( $type ) ) {
return $type;
}
/**
* Filter 'redux/options/{opt_name}/pre_data/{type}'
*
* @param string $data
*/
$pre_data = apply_filters( "redux/options/$opt_name/pre_data/$type", null ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
if ( null !== $pre_data || empty( $type ) ) {
return $pre_data;
}
if ( isset( $args['data_sortby'] ) && in_array( $args['data_sortby'], array( 'value', 'key' ), true ) ) {
$data_sort = $args['data_sortby'];
unset( $args['data_sortby'] );
} else {
$data_sort = 'value';
}
if ( isset( $args['data_order'] ) && in_array( $args['data_order'], array( 'asc', 'desc' ), true ) ) {
$data_order = $args['data_order'];
unset( $args['data_order'] );
} else {
$data_order = 'asc';
}
$this->maybe_get_translation( $type, $current_value, $args );
$current_data = array();
if ( empty( $current_value ) && ! Redux_Helpers::is_integer( $current_value ) ) {
$current_value = null;
} else {
// Get the args to grab the current data.
$current_data_args = $this->get_current_data_args( $type, $args, $current_value );
// Let's make a unique key for this arg array.
$current_data_args_key = md5( maybe_serialize( $current_data_args ) );
// Check to make sure we haven't already run this call before.
$current_data = $this->wp_data[ $type . $current_data_args_key ] ?? $this->get_data( $type, $current_data_args, $current_value );
}
// If ajax is enabled AND $current_data is empty, set a dummy value for the init.
if ( $ajax && ! wp_doing_ajax() ) {
// Dummy is needed otherwise empty.
if ( empty( $current_data ) ) {
$current_data = array(
'dummy' => '',
);
}
return $current_data;
}
// phpcs:ignore Squiz.PHP.CommentedOutCode
$args_key = md5( maybe_serialize( $args ) );
// Data caching.
if ( isset( $this->wp_data[ $type . $args_key ] ) ) {
$data = $this->wp_data[ $type . $args_key ];
} else {
/**
* Use data from WordPress to populate options array.
* */
$data = $this->get_data( $type, $args, $current_value );
}
if ( ! empty( $current_data ) ) {
$data += $current_data;
}
if ( ! empty( $data ) ) {
$data = $this->order_data( $data, $data_sort, $data_order );
$this->wp_data[ $type . $args_key ] = $data;
}
/**
* Filter 'redux/options/{opt_name}/data/{type}'
*
* @param string $data
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
return apply_filters( "redux/options/$opt_name/data/$type", $data );
}
/**
* Process the results into a proper array, fetching the data elements needed for each data type.
*
* @param array|WP_Error $results Results to process in the data array.
* @param string|bool $id_key Key on object/array that represents the ID.
* @param string|bool $name_key Key on object/array that represents the name/text.
* @param bool $add_key If true, the display key will appear in the text.
* @param string|bool $secondary_key If a data type you'd rather display a different ID as the display key.
*
* @return array
*/
private function process_results( $results = array(), $id_key = '', $name_key = '', bool $add_key = true, $secondary_key = 'slug' ): array {
$data = array();
if ( ! empty( $results ) && ! is_a( $results, 'WP_Error' ) ) {
foreach ( $results as $k => $v ) {
if ( empty( $id_key ) ) {
$key = $k;
} else {
if ( is_object( $v ) ) {
$key = $v->$id_key;
} elseif ( is_array( $v ) ) {
$key = $v[ $id_key ];
} else {
$key = $k;
}
}
if ( empty( $name_key ) ) {
$value = $v;
} else {
if ( is_object( $v ) ) {
$value = $v->$name_key;
} elseif ( is_array( $v ) ) {
$value = $v[ $name_key ];
} else {
$value = $v;
}
}
$display_key = $key;
if ( is_object( $v ) && isset( $v->$secondary_key ) ) {
$display_key = $v->$secondary_key;
} elseif ( ! is_object( $v ) && isset( $v[ $secondary_key ] ) ) {
$display_key = $v[ $secondary_key ];
}
$data[ $key ] = $value;
if ( $display_key !== $value && $add_key ) {
$data[ $key ] = $data[ $key ] . ' [' . $display_key . ']';
}
}
}
return $data;
}
/**
* Order / Sort the data.
*
* @param array $data Data to sort.
* @param string $sort Way to sort. Accepts: key|value.
* @param string $order Order of the sort. Accepts: asc|desc.
*
* @return array
*/
private function order_data( array $data = array(), string $sort = 'value', string $order = 'asc' ): array {
if ( 'key' === $sort ) {
if ( 'asc' === $order ) {
ksort( $data );
} else {
krsort( $data );
}
} elseif ( 'value' === $sort ) {
if ( 'asc' === $order ) {
asort( $data );
} else {
arsort( $data );
}
}
return $data;
}
/**
* Fetch the data for a given type.
*
* @param string $type The data type we're fetching.
* @param array|string $args Arguments to pass.
* @param mixed|array $current_value If a current value already set in the database.
*
* @return array|null|string
*/
private function get_data( string $type, $args, $current_value ) {
$args = $this->get_arg_defaults( $type, $args );
$opt_name = $this->opt_name;
if ( empty( $args ) ) {
$args = array();
}
$data = array();
if ( isset( $args['args'] ) && empty( $args['args'] ) ) {
unset( $args['args'] );
}
$display_keys = false;
if ( isset( $args['display_keys'] ) ) {
$display_keys = true;
unset( $args['display_keys'] );
}
$secondary_key = 'slug';
if ( isset( $args['secondary_key'] ) ) {
$secondary_key = $args['secondary_key'];
unset( $args['secondary_key'] );
}
switch ( $type ) {
case 'categories':
case 'category':
case 'terms':
case 'term':
if ( isset( $args['taxonomies'] ) ) {
$args['taxonomy'] = $args['taxonomies'];
unset( $args['taxonomies'] );
}
$results = get_terms( $args );
$data = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
break;
case 'pages':
case 'page':
$results = get_pages( $args );
$data = $this->process_results( $results, 'ID', 'post_title', $display_keys, $secondary_key );
break;
case 'tags':
case 'tag':
$results = get_tags( $args );
$data = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
break;
case 'menus':
case 'menu':
$results = wp_get_nav_menus( $args );
$data = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
break;
case 'posts':
case 'post':
$results = get_posts( $args );
$data = $this->process_results( $results, 'ID', 'post_title', $display_keys, $secondary_key );
break;
case 'users':
case 'user':
$results = get_users( $args );
$data = $this->process_results( $results, 'ID', 'display_name', $display_keys, $secondary_key );
break;
case 'sites':
case 'site':
$sites = get_sites();
if ( isset( $sites ) ) {
$results = array();
foreach ( $sites as $site ) {
$site = (array) $site;
$k = $site['blog_id'];
$v = $site['domain'] . $site['path'];
$name = get_blog_option( $k, 'blogname' );
if ( ! empty( $name ) ) {
$v .= ' - [' . $name . ']';
}
$results[ $k ] = $v;
}
$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
}
break;
case 'taxonomies':
case 'taxonomy':
case 'tax':
$results = get_taxonomies( $args );
$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
break;
case 'post_types':
case 'post_type':
global $wp_post_types;
$output = $args['output'];
unset( $args['output'] );
$operator = $args['operator'];
unset( $args['operator'] );
$post_types = get_post_types( $args, $output, $operator );
foreach ( $post_types as $name => $title ) {
if ( isset( $wp_post_types[ $name ]->labels->menu_name ) ) {
$data[ $name ] = $wp_post_types[ $name ]->labels->menu_name;
} else {
$data[ $name ] = ucfirst( $name );
}
}
break;
case 'menu_locations':
case 'menu_location':
global $_wp_registered_nav_menus;
foreach ( $_wp_registered_nav_menus as $k => $v ) {
$data[ $k ] = $v;
if ( ! has_nav_menu( $k ) ) {
$data[ $k ] .= ' ' . __( '[unassigned]', 'redux-framework' );
}
}
break;
case 'image_sizes':
case 'image_size':
global $_wp_additional_image_sizes;
$results = array();
foreach ( $_wp_additional_image_sizes as $size_name => $size_attrs ) {
$results[ $size_name ] = $size_name . ' - ' . $size_attrs['width'] . ' x ' . $size_attrs['height'];
}
$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
break;
case 'elusive-icons':
case 'elusive-icon':
case 'elusive':
case 'icons':
case 'font-icon':
case 'font-icons':
$fs = Redux_Filesystem::get_instance();
$fonts = $fs->get_contents( Redux_Core::$dir . 'assets/css/vendor/elusive-icons.css' );
if ( ! empty( $fonts ) ) {
preg_match_all( '@\.el-(\w+)::before@', $fonts, $matches );
foreach ( $matches[1] as $item ) {
if ( 'before' === $item ) {
continue;
}
$data[ 'el el-' . $item ] = $item;
}
}
/**
* Filter 'redux/font-icons'
*
* @param array $font_icons array of elusive icon classes
*
* @deprecated
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$font_icons = apply_filters_deprecated( 'redux/font-icons', array( $data ), '4.3', 'redux/$opt_name/field/font/icons' );
/**
* Filter 'redux/{opt_name}/field/font/icons'
*
* @param array $font_icons array of elusive icon classes
*/
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$data = apply_filters( "redux/$opt_name/field/font/icons", $font_icons );
break;
case 'dashicons':
case 'dashicon':
case 'dash':
$fs = Redux_Filesystem::get_instance();
$fonts = $fs->get_contents( ABSPATH . WPINC . '/css/dashicons.css' );
if ( ! empty( $fonts ) ) {
preg_match_all( '@\.dashicons-(\w+):before@', $fonts, $matches );
foreach ( $matches[1] as $item ) {
if ( 'before' === $item ) {
continue;
}
$data[ 'dashicons dashicons-' . $item ] = $item;
}
}
break;
case 'roles':
case 'role':
global $wp_roles;
$results = $wp_roles->get_names();
$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
break;
case 'sidebars':
case 'sidebar':
global $wp_registered_sidebars;
$data = $this->process_results( $wp_registered_sidebars, '', 'name', $display_keys, $secondary_key );
break;
case 'capabilities':
case 'capability':
global $wp_roles;
$results = array();
foreach ( $wp_roles->roles as $role ) {
foreach ( $role['capabilities'] as $key => $cap ) {
$results[ $key ] = ucwords( str_replace( '_', ' ', $key ) );
}
}
$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
break;
case 'capabilities_grouped':
case 'capability_grouped':
case 'capabilities_group':
case 'capability_group':
global $wp_roles;
foreach ( $wp_roles->roles as $role ) {
$caps = array();
foreach ( $role['capabilities'] as $key => $cap ) {
$caps[ $key ] = ucwords( str_replace( '_', ' ', $key ) );
}
asort( $caps );
$data[ $role['name'] ] = $caps;
}
break;
case 'callback':
if ( ! empty( $args ) && is_string( $args ) && function_exists( $args ) ) {
$data = call_user_func( $args, $current_value );
}
break;
}
return $data;
}
/**
* Router for translation based on the given post type.
*
* @param string $type Type of data request.
* @param mixed|array $current_value Current value stored in DB.
* @param array|string $args Arguments for the call.
*/
private function maybe_get_translation( string $type, &$current_value = '', $args = array() ) {
switch ( $type ) {
case 'categories':
case 'category':
$this->maybe_translate( $current_value, 'category' );
break;
case 'pages':
case 'page':
$this->maybe_translate( $current_value, 'page' );
break;
case 'terms':
case 'term':
$this->maybe_translate( $current_value, $args['taxonomy'] ?? '' );
break;
case 'tags':
case 'tag':
$this->maybe_translate( $current_value, 'post_tag' );
break;
case 'menus':
case 'menu':
$this->maybe_translate( $current_value, 'nav_menu' );
break;
case 'post':
case 'posts':
$this->maybe_translate( $current_value, 'post' );
break;
default:
$this->maybe_translate( $current_value, '' );
}
}
/**
* Maybe translate the values.
*
* @param mixed|array $value Value.
* @param mixed|array $post_type Post type.
*/
private function maybe_translate( &$value, $post_type ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$value = apply_filters( "redux/options/$this->opt_name/wordpress_data/translate/post_type_value", $value, $post_type );
// WPML Integration, see https://wpml.org/documentation/support/creating-multilingual-wordpress-themes/language-dependent-ids/.
if ( function_exists( 'icl_object_id' ) ) {
if ( has_filter( 'wpml_object_id' ) ) {
if ( Redux_Helpers::is_integer( $value ) ) {
$value = apply_filters( 'wpml_object_id', $value, $post_type, true );
} elseif ( is_array( $value ) ) {
$value = array_map(
function ( $val ) use ( $post_type ) {
return apply_filters( 'wpml_object_id', $val, $post_type, true );
},
$value
);
}
}
}
}
/**
* Set the default arguments for a current query (existing data).
*
* @param string $type Type of data request.
* @param array|string $args Arguments for the call.
* @param mixed|array $current_value Current value stored in DB.
*
* @return array
*/
private function get_current_data_args( string $type, $args, $current_value ): array {
// In this section we set the default arguments for each data type.
switch ( $type ) {
case 'categories':
case 'category':
case 'pages':
case 'page':
case 'terms':
case 'term':
case 'users':
case 'user':
$args['include'] = $current_value;
break;
case 'tags':
case 'tag':
$args['get'] = 'all';
break;
case 'menus':
case 'menu':
$args['object_ids'] = $current_value;
break;
case 'post':
case 'posts':
if ( ! empty( $current_value ) ) {
$args['post__in'] = is_array( $current_value ) ? $current_value : array( $current_value );
}
break;
default:
$args = array();
}
return $args;
}
/**
* Get default arguments for a given data type.
*
* @param string $type Type of data request.
* @param array|string $args Arguments for the call.
*
* @return array|string
*/
private function get_arg_defaults( string $type, $args = array() ) {
// In this section we set the default arguments for each data type.
switch ( $type ) {
case 'categories':
case 'category':
$args = wp_parse_args(
$args,
array(
'taxonomy' => 'category',
)
);
break;
case 'pages':
case 'page':
$args = wp_parse_args(
$args,
array(
'display_keys' => true,
'posts_per_page' => 20,
)
);
break;
case 'post_type':
case 'post_types':
$args = wp_parse_args(
$args,
array(
'public' => true,
'exclude_from_search' => false,
'output' => 'names',
'operator' => 'and',
)
);
break;
case 'tag':
case 'tags':
$args = wp_parse_args(
$args,
array(
'get' => 'all',
'display_keys' => true,
)
);
break;
case 'sidebars':
case 'sidebar':
case 'capabilities':
case 'capability':
$args = wp_parse_args(
$args,
array(
'display_keys' => true,
)
);
break;
case 'capabilities_grouped':
case 'capability_grouped':
case 'capabilities_group':
case 'capability_group':
$args = wp_parse_args(
$args,
array(
'data_sortby' => '',
)
);
break;
}
return $args;
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;