Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
wp-content
/
plugins
/
wordpress-seo
/
src
/
deprecated
/
src
/
helpers
:
controls-stack.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?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(); $