• File: controls-stack.php
  • Full Path: /home/blwgracecity/jesusexp.org/wp-content/plugins/wordpress-seo/src/deprecated/src/helpers/controls-stack.php
  • File size: 16 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php
namespace Elementor;

use Elementor\Core\Base\Base_Object;
use Elementor\Core\DynamicTags\Manager;
use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
use Elementor\Core\Frontend\Performance;
use Elementor\Utils;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor controls stack.
 *
 * An abstract class that provides the needed properties and methods to
 * manage and handle controls in the editor panel to inheriting classes.
 *
 * @since 1.4.0
 * @abstract
 */
abstract class Controls_Stack extends Base_Object {

	/**
	 * Responsive 'desktop' device name.
	 *
	 * @deprecated 3.4.0
	 */
	const RESPONSIVE_DESKTOP = 'desktop';

	/**
	 * Responsive 'tablet' device name.
	 *
	 * @deprecated 3.4.0
	 */
	const RESPONSIVE_TABLET = 'tablet';

	/**
	 * Responsive 'mobile' device name.
	 *
	 * @deprecated 3.4.0
	 */
	const RESPONSIVE_MOBILE = 'mobile';

	/**
	 * Generic ID.
	 *
	 * Holds the unique ID.
	 *
	 * @access private
	 *
	 * @var string
	 */
	private $id;

	private $active_settings;

	private $parsed_active_settings;

	/**
	 * Parsed Dynamic Settings.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $parsed_dynamic_settings;

	/**
	 * Raw Data.
	 *
	 * Holds all the raw data including the element type, the child elements,
	 * the user data.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $data;

	/**
	 * The configuration.
	 *
	 * Holds the configuration used to generate the Elementor editor. It includes
	 * the element name, icon, categories, etc.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $config;

	/**
	 * The additional configuration.
	 *
	 * Holds additional configuration that has been set using `set_config` method.
	 * The `config` property is not modified directly while using the method because
	 * it's used to check whether the initial config already loaded (in `get_config`).
	 * After the initial config loaded, the additional config is merged into it.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $additional_config = [];

	/**
	 * Current section.
	 *
	 * Holds the current section while inserting a set of controls sections.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $current_section;

	/**
	 * Current tab.
	 *
	 * Holds the current tab while inserting a set of controls tabs.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $current_tab;

	/**
	 * Current popover.
	 *
	 * Holds the current popover while inserting a set of controls.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $current_popover;

	/**
	 * Injection point.
	 *
	 * Holds the injection point in the stack where the control will be inserted.
	 *
	 * @access private
	 *
	 * @var null|array
	 */
	private $injection_point;


	/**
	 * Data sanitized.
	 *
	 * @access private
	 *
	 * @var bool
	 */
	private $settings_sanitized = false;

	/**
	 * Element render attributes.
	 *
	 * Holds all the render attributes of the element. Used to store data like
	 * the HTML class name and the class value, or HTML element ID name and value.
	 *
	 * @access private
	 *
	 * @var array
	 */
	private $render_attributes = [];

	/**
	 * Get element name.
	 *
	 * Retrieve the element name.
	 *
	 * @since 1.4.0
	 * @access public
	 * @abstract
	 *
	 * @return string The name.
	 */
	abstract public function get_name();

	/**
	 * Get unique name.
	 *
	 * Some classes need to use unique names, this method allows you to create
	 * them. By default it retrieves the regular name.
	 *
	 * @since 1.6.0
	 * @access public
	 *
	 * @return string Unique name.
	 */
	public function get_unique_name() {
		return $this->get_name();
	}

	/**
	 * Get element ID.
	 *
	 * Retrieve the element generic ID.
	 *
	 * @since 1.4.0
	 * @access public
	 *
	 * @return string The ID.
	 */
	public function get_id() {
		return $this->id;
	}

	/**
	 * Get element ID.
	 *
	 * Retrieve the element generic ID as integer.
	 *
	 * @since 1.8.0
	 * @access public
	 *
	 * @return string The converted ID.
	 */
	public function get_id_int() {
		/** We ignore possible notices, in order to support elements created prior to v1.8.0 and might include
		 *  non-base 16 characters as part of their ID.
		 */
		return @hexdec( $this->id );
	}

	/**
	 * Get widget number.
	 *
	 * Get the first three numbers of the element converted ID.
	 *
	 * @since 3.16
	 * @access public
	 *
	 * @return string The widget number.
	 */
	public function get_widget_number(): string {
		return substr( $this->get_id_int(), 0, 3 );
	}

	/**
	 * Get the type.
	 *
	 * Retrieve the type, e.g. 'stack', 'section', 'widget' etc.
	 *
	 * @since 1.4.0
	 * @access public
	 * @static
	 *
	 * @return string The type.
	 */
	public static function get_type() {
		return 'stack';
	}

	/**
	 * @since 2.9.0
	 * @access public
	 *
	 * @return bool
	 */
	public function is_editable() {
		return true;
	}

	/**
	 * Get current section.
	 *
	 * When inserting new controls, this method will retrieve the current section.
	 *
	 * @since 1.7.1
	 * @access public
	 *
	 * @return null|array Current section.
	 */
	public function get_current_section() {
		return $this->current_section;
	}

	/**
	 * Get current tab.
	 *
	 * When inserting new controls, this method will retrieve the current tab.
	 *
	 * @since 1.7.1
	 * @access public
	 *
	 * @return null|array Current tab.
	 */
	public function get_current_tab() {
		return $this->current_tab;
	}

	/**
	 * Get controls.
	 *
	 * Retrieve all the controls or, when requested, a specific control.
	 *
	 * @since 1.4.0
	 * @access public
	 *
	 * @param string $control_id The ID of the requested control. Optional field,
	 *                           when set it will return a specific control.
	 *                           Default is null.
	 *
	 * @return mixed Controls list.
	 */
	public function get_controls( $control_id = null ) {
		$stack = $this->get_stack();

		if ( null !== $control_id ) {
			$control_data = self::get_items( $stack['controls'], $control_id );
			if ( null === $control_data && ! empty( $stack['style_controls'] ) ) {
				$control_data = self::get_items( $stack['style_controls'], $control_id );
			}

			return $control_data;
		}

		$controls = $stack['controls'];

		if ( Performance::is_use_style_controls() && ! empty( $stack['style_controls'] ) ) {
			$controls += $stack['style_controls'];
		}

		return self::get_items( $controls, $control_id );
	}

	/**
	 * Get active controls.
	 *
	 * Retrieve an array of active controls that meet the condition field.
	 *
	 * If specific controls was given as a parameter, retrieve active controls
	 * from that list, otherwise check for all the controls available.
	 *
	 * @since 1.4.0
	 * @since 2.0.9 Added the `controls` and the `settings` parameters.
	 * @access public
	 * @deprecated 3.0.0
	 *
	 * @param array $controls Optional. An array of controls. Default is null.
	 * @param array $settings Optional. Controls settings. Default is null.
	 *
	 * @return array Active controls.
	 */
	public function get_active_controls( array $controls = null, array $settings = null ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.0.0' );

		if ( ! $controls ) {
			$controls = $this->get_controls();
		}

		if ( ! $settings ) {
			$settings = $this->get_controls_settings();
		}

		$active_controls = array_reduce(
			array_keys( $controls ), function( $active_controls, $control_key ) use ( $controls, $settings ) {
				$control = $controls[ $control_key ];

				if ( $this->is_control_visible( $control, $settings, $controls ) ) {
					$active_controls[ $control_key ] = $control;
				}

				return $active_controls;
			}, []
		);

		return $active_controls;
	}

	/**
	 * Get controls settings.
	 *
	 * Retrieve the settings for all the controls that represent them.
	 *
	 * @since 1.5.0
	 * @access public
	 *
	 * @return array Controls settings.
	 */
	public function get_controls_settings() {
		return array_intersect_key( $this->get_settings(), $this->get_controls() );
	}

	/**
	 * Add new control to stack.
	 *
	 * Register a single control to allow the user to set/update data.
	 *
	 * This method should be used inside `register_controls()`.
	 *
	 * @since 1.4.0
	 * @access public
	 *
	 * @param string $id      Control ID.
	 * @param array  $args    Control arguments.
	 * @param array  $options Optional. Control options. Default is an empty array.
	 *
	 * @return bool True if control added, False otherwise.
	 */
	public function add_control( $id, array $args, $options = [] ) {
		$default_options = [
			'overwrite' => false,
			'position' => null,
		];

		if ( isset( $args['scheme'] ) ) {
			$args['global'] = [
				'default' => Plugin::$instance->kits_manager->convert_scheme_to_global( $args['scheme'] ),
			];

			unset( $args['scheme'] );
		}

		$options = array_merge( $default_options, $options );

		if ( $options['position'] ) {
			$this->start_injection( $options['position'] );
		}

		if ( $this->injection_point ) {
			$options['index'] = $this->injection_point['index']++;
		}

		if ( empty( $args['type'] ) || ! in_array( $args['type'], [ Controls_Manager::SECTION, Controls_Manager::WP_WIDGET ], true ) ) {
			$args = $this->handle_control_position( $args, $id, $options['overwrite'] );
		}

		if ( $options['position'] ) {
			$this->end_injection();
		}

		unset( $options['position'] );

		if ( $this->current_popover ) {
			$args['popover'] = [];

			if ( ! $this->current_popover['initialized'] ) {
				$args['popover']['start'] = true;

				$this->current_popover['initialized'] = true;
			}
		}

		if ( Performance::should_optimize_controls() ) {
			$ui_controls = [
				Controls_Manager::RAW_HTML,
				Controls_Manager::DIVIDER,
				Controls_Manager::HEADING,
				Controls_Manager::BUTTON,
				Controls_Manager::ALERT,
				Controls_Manager::NOTICE,
				Controls_Manager::DEPRECATED_NOTICE,
			];

			if ( ! empty( $args['type'] ) && ! empty( $args['section'] ) && in_array( $args['type'], $ui_controls ) ) {
				$args = [
					'type' => $args['type'],
					'section' => $args['section'],
				];
			}

			unset(
				$args['label_block'],
				$args['label'],
				$args['title'],
				$args['tab'],
				$args['options'],
				$args['placeholder'],
				$args['separator'],
				$args['size_units'],
				$args['range'],
				$args['toggle'],
				$args['ai'],
				$args['classes'],
				$args['style_transfer'],
				$args['show_label'],
				$args['description'],
				$args['label_on'],
				$args['label_off'],
				$args['labels'],
				$args['handles'],
				$args['editor_available'],
			);
		}

		return Plugin::$instance->controls_manager->add_control_to_stack( $this, $id, $args, $options );
	}

	/**
	 * Remove control from stack.
	 *
	 * Unregister an existing control and remove it from the stack.
	 *
	 * @since 1.4.0
	 * @access public
	 *
	 * @param string $control_id Control ID.
	 *
	 * @return bool|\WP_Error
	 */
	public function remove_control( $control_id ) {
		return Plugin::$instance->controls_manager->remove_control_from_stack( $this->get_unique_name(), $control_id );
	}

	/**
	 * Update control in stack.
	 *
	 * Change the value of an existing control in the stack. When you add new
	 * control you set the `$args` parameter, this method allows you to update
	 * the arguments by passing new data.
	 *
	 * @since 1.4.0
	 * @since 1.8.1 New `$options` parameter added.
	 *
	 * @access public
	 *
	 * @param string $control_id Control ID.
	 * @param array  $args       Control arguments. Only the new fields you want
	 *                           to update.
	 * @param array  $options    Optional. Some additional options. Default is
	 *                           an empty array.
	 *
	 * @return bool
	 */
	public function update_control( $control_id, array $args, array $options = [] ) {
		$is_updated = Plugin::$instance->controls_manager->update_control_in_stack( $this, $control_id, $args, $options );

		if ( ! $is_updated ) {
			return false;
		}

		$control = $this->get_controls( $control_id );

		if ( Controls_Manager::SECTION === $control['type'] ) {
			$section_args = $this->get_section_args( $control_id );

			$section_controls = $this->get_section_controls( $control_id );

			foreach ( $section_controls as $section_control_id => $section_control ) {
				$this->update_control( $section_control_id, $section_args, $options );
			}
		}

		return true;
	}

	/**
	 * Get stack.
	 *
	 * Retrieve the stack of controls.
	 *
	 * @since 1.9.2
	 * @access public
	 *
	 * @return array Stack of controls.
	 */
	public function get_stack() {
		$stack = Plugin::$instance->controls_manager->get_element_stack( $this );

		if ( null === $stack ) {
			$this->init_controls();

			return Plugin::$instance->controls_manager->get_element_stack( $this );
		}

		return $stack;
	}

	/**
	 * Get position information.
	 *
	 * Retrieve the position while injecting data, based on the element type.
	 *
	 * @since 1.7.0
	 * @access public
	 *
	 * @param array $position {
	 *     The injection position.
	 *
	 *     @type string $type     Injection type, either `control` or `section`.
	 *                            Default is `control`.
	 *     @type string $at       Where to inject. If `$type` is `control` accepts
	 *                            `before` and `after`. If `$type` is `section`
	 *                            accepts `start` and `end`. Default values based on
	 *                            the `type`.
	 *     @type string $of       Control/Section ID.
	 *     @type array  $fallback Fallback injection position. When the position is
	 *                            not found it will try to fetch the fallback
	 *                            position.
	 * }
	 *
	 * @return bool|array Position info.
	 */
	final public function get_position_info( array $position ) {
		$default_position = [
			'type' => 'control',
			'at' => 'after',
		];

		if ( ! empty( $position['type'] ) && 'section' === $position['type'] ) {
			$default_position['at'] = 'end';
		}

		$position = array_merge( $default_position, $position );

		if (
			( 'control' === $position['type'] && in_array( $position['at'], [ 'start', 'end' ], true ) ) ||
			( 'section' === $position['type'] && in_array( $position['at'], [ 'before', 'after' ], true ) )
		) {
			_doing_it_wrong( sprintf( '%s::%s', get_called_class(), __FUNCTION__ ), 'Invalid position arguments. Use `before` / `after` for control or `start` / `end` for section.', '1.7.0' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

			return false;
		}

		$target_control_index = $this->get_control_index( $position['of'] );

		if ( false === $target_control_index ) {
			if ( ! empty( $position['fallback'] ) ) {
				return $this->get_position_info( $position['fallback'] );
			}

			return false;
		}

		$target_section_index = $target_control_index;

		$registered_controls = $this->get_controls();

		$controls_keys = array_keys( $registered_controls );

		while ( Controls_Manager::SECTION !== $registered_controls[ $controls_keys[ $target_section_index ] ]['type'] ) {
			--$target_section_index;
		}

		if ( 'section' === $position['type'] ) {
			++$target_control_index;

			if ( 'end' === $position['at'] ) {
				while ( Controls_Manager::SECTION !== $registered_controls[ $controls_keys[ $target_control_index ] ]['type'] ) {
					if ( ++$target_control_index >= count( $registered_controls ) ) {
						break;
					}
				}
			}
		}

		$target_control = $registered_controls[ $controls_keys[ $target_control_index ] ];

		if ( 'after' === $position['at'] ) {
			++$target_control_index;
		}

		$section_id = $registered_controls[ $controls_keys[ $target_section_index ] ]['name'];

		$position_info = [
			'index' => $target_control_index,
			'section' => $this->get_section_args( $section_id ),
		];

		if ( ! empty( $target_control['tabs_wrapper'] ) ) {
			$position_info['tab'] = [
				'tabs_wrapper' => $target_control['tabs_wrapper'],
				'inner_tab' => $target_control['inner_tab'],
			];
		}

		return $position_info;
	}

	/**
	 * Get control key.
	 *
	 * Retrieve the key of the control based on a given index of the control.
	 *
	 * @since 1.9.2
	 * @access public
	 *
	 * @param string $control_index Control index.
	 *
	 * @return int Control key.
	 */
	final public function get_control_key( $control_index ) {
		$registered_controls = $this->get_controls();

		$