SHARE
TWEET

Untitled

a guest Jul 16th, 2019 72 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. namespace Elementor;
  3.  
  4. use Elementor\Core\Base\Base_Object;
  5. use Elementor\Core\DynamicTags\Manager;
  6.  
  7. if ( ! defined( 'ABSPATH' ) ) {
  8.     exit; // Exit if accessed directly.
  9. }
  10.  
  11. /**
  12.  * Elementor controls stack.
  13.  *
  14.  * An abstract class that provides the needed properties and methods to
  15.  * manage and handle controls in the editor panel to inheriting classes.
  16.  *
  17.  * @since 1.4.0
  18.  * @abstract
  19.  */
  20. abstract class Controls_Stack extends Base_Object {
  21.  
  22.     /**
  23.      * Responsive 'desktop' device name.
  24.      */
  25.     const RESPONSIVE_DESKTOP = 'desktop';
  26.  
  27.     /**
  28.      * Responsive 'tablet' device name.
  29.      */
  30.     const RESPONSIVE_TABLET = 'tablet';
  31.  
  32.     /**
  33.      * Responsive 'mobile' device name.
  34.      */
  35.     const RESPONSIVE_MOBILE = 'mobile';
  36.  
  37.     /**
  38.      * Generic ID.
  39.      *
  40.      * Holds the unique ID.
  41.      *
  42.      * @access private
  43.      *
  44.      * @var string
  45.      */
  46.     private $id;
  47.  
  48.     private $active_settings;
  49.  
  50.     private $parsed_active_settings;
  51.  
  52.     /**
  53.      * Parsed Dynamic Settings.
  54.      *
  55.      * @access private
  56.      *
  57.      * @var null|array
  58.      */
  59.     private $parsed_dynamic_settings;
  60.  
  61.     /**
  62.      * Raw Data.
  63.      *
  64.      * Holds all the raw data including the element type, the child elements,
  65.      * the user data.
  66.      *
  67.      * @access private
  68.      *
  69.      * @var null|array
  70.      */
  71.     private $data;
  72.  
  73.     /**
  74.      * The configuration.
  75.      *
  76.      * Holds the configuration used to generate the Elementor editor. It includes
  77.      * the element name, icon, categories, etc.
  78.      *
  79.      * @access private
  80.      *
  81.      * @var null|array
  82.      */
  83.     private $config;
  84.  
  85.     /**
  86.      * Current section.
  87.      *
  88.      * Holds the current section while inserting a set of controls sections.
  89.      *
  90.      * @access private
  91.      *
  92.      * @var null|array
  93.      */
  94.     private $current_section;
  95.  
  96.     /**
  97.      * Current tab.
  98.      *
  99.      * Holds the current tab while inserting a set of controls tabs.
  100.      *
  101.      * @access private
  102.      *
  103.      * @var null|array
  104.      */
  105.     private $current_tab;
  106.  
  107.     /**
  108.      * Current popover.
  109.      *
  110.      * Holds the current popover while inserting a set of controls.
  111.      *
  112.      * @access private
  113.      *
  114.      * @var null|array
  115.      */
  116.     private $current_popover;
  117.  
  118.     /**
  119.      * Injection point.
  120.      *
  121.      * Holds the injection point in the stack where the control will be inserted.
  122.      *
  123.      * @access private
  124.      *
  125.      * @var null|array
  126.      */
  127.     private $injection_point;
  128.  
  129.  
  130.     /**
  131.      * Data sanitized.
  132.      *
  133.      * @access private
  134.      *
  135.      * @var bool
  136.      */
  137.     private $settings_sanitized = false;
  138.  
  139.     /**
  140.      * Get element name.
  141.      *
  142.      * Retrieve the element name.
  143.      *
  144.      * @since 1.4.0
  145.      * @access public
  146.      * @abstract
  147.      *
  148.      * @return string The name.
  149.      */
  150.     abstract public function get_name();
  151.  
  152.     /**
  153.      * Get unique name.
  154.      *
  155.      * Some classes need to use unique names, this method allows you to create
  156.      * them. By default it retrieves the regular name.
  157.      *
  158.      * @since 1.6.0
  159.      * @access public
  160.      *
  161.      * @return string Unique name.
  162.      */
  163.     public function get_unique_name() {
  164.         return $this->get_name();
  165.     }
  166.  
  167.     /**
  168.      * Get element ID.
  169.      *
  170.      * Retrieve the element generic ID.
  171.      *
  172.      * @since 1.4.0
  173.      * @access public
  174.      *
  175.      * @return string The ID.
  176.      */
  177.     public function get_id() {
  178.         return $this->id;
  179.     }
  180.  
  181.     /**
  182.      * Get element ID.
  183.      *
  184.      * Retrieve the element generic ID as integer.
  185.      *
  186.      * @since 1.8.0
  187.      * @access public
  188.      *
  189.      * @return string The converted ID.
  190.      */
  191.     public function get_id_int() {
  192.         return hexdec( $this->id );
  193.     }
  194.  
  195.     /**
  196.      * Get the type.
  197.      *
  198.      * Retrieve the type, e.g. 'stack', 'section', 'widget' etc.
  199.      *
  200.      * @since 1.4.0
  201.      * @access public
  202.      * @static
  203.      *
  204.      * @return string The type.
  205.      */
  206.     public static function get_type() {
  207.         return 'stack';
  208.     }
  209.  
  210.     /**
  211.      * Get items.
  212.      *
  213.      * Utility method that receives an array with a needle and returns all the
  214.      * items that match the needle. If needle is not defined the entire haystack
  215.      * will be returned.
  216.      *
  217.      * @since 1.4.0
  218.      * @deprecated 2.3.0 Use `Controls_Stack::get_items()` instead
  219.      * @access protected
  220.      * @static
  221.      *
  222.      * @param array  $haystack An array of items.
  223.      * @param string $needle   Optional. Needle. Default is null.
  224.      *
  225.      * @return mixed The whole haystack or the needle from the haystack when requested.
  226.      */
  227.     protected static function _get_items( array $haystack, $needle = null ) {
  228.         // _deprecated_function( __METHOD__, '2.3.0', __CLASS__ . '::get_items()' );
  229.  
  230.         if ( $needle ) {
  231.             return isset( $haystack[ $needle ] ) ? $haystack[ $needle ] : null;
  232.         }
  233.  
  234.         return $haystack;
  235.     }
  236.  
  237.     /**
  238.      * Get current section.
  239.      *
  240.      * When inserting new controls, this method will retrieve the current section.
  241.      *
  242.      * @since 1.7.1
  243.      * @access public
  244.      *
  245.      * @return null|array Current section.
  246.      */
  247.     public function get_current_section() {
  248.         return $this->current_section;
  249.     }
  250.  
  251.     /**
  252.      * Get current tab.
  253.      *
  254.      * When inserting new controls, this method will retrieve the current tab.
  255.      *
  256.      * @since 1.7.1
  257.      * @access public
  258.      *
  259.      * @return null|array Current tab.
  260.      */
  261.     public function get_current_tab() {
  262.         return $this->current_tab;
  263.     }
  264.  
  265.     /**
  266.      * Get controls.
  267.      *
  268.      * Retrieve all the controls or, when requested, a specific control.
  269.      *
  270.      * @since 1.4.0
  271.      * @access public
  272.      *
  273.      * @param string $control_id The ID of the requested control. Optional field,
  274.      *                           when set it will return a specific control.
  275.      *                           Default is null.
  276.      *
  277.      * @return mixed Controls list.
  278.      */
  279.     public function get_controls( $control_id = null ) {
  280.         return self::get_items( $this->get_stack()['controls'], $control_id );
  281.     }
  282.  
  283.     /**
  284.      * Get active controls.
  285.      *
  286.      * Retrieve an array of active controls that meet the condition field.
  287.      *
  288.      * If specific controls was given as a parameter, retrieve active controls
  289.      * from that list, otherwise check for all the controls available.
  290.      *
  291.      * @since 1.4.0
  292.      * @since 2.0.9 Added the `controls` and the `settings` parameters.
  293.      * @access public
  294.      *
  295.      * @param array $controls Optional. An array of controls. Default is null.
  296.      * @param array $settings Optional. Controls settings. Default is null.
  297.      *
  298.      * @return array Active controls.
  299.      */
  300.     public function get_active_controls( array $controls = null, array $settings = null ) {
  301.         if ( ! $controls ) {
  302.             $controls = $this->get_controls();
  303.         }
  304.  
  305.         if ( ! $settings ) {
  306.             $settings = $this->get_controls_settings();
  307.         }
  308.  
  309.         $active_controls = array_reduce(
  310.             array_keys( $controls ), function( $active_controls, $control_key ) use ( $controls, $settings ) {
  311.                 $control = $controls[ $control_key ];
  312.  
  313.                 if ( $this->is_control_visible( $control, $settings ) ) {
  314.                     $active_controls[ $control_key ] = $control;
  315.                 }
  316.  
  317.                 return $active_controls;
  318.             }, []
  319.         );
  320.  
  321.         return $active_controls;
  322.     }
  323.  
  324.     /**
  325.      * Get controls settings.
  326.      *
  327.      * Retrieve the settings for all the controls that represent them.
  328.      *
  329.      * @since 1.5.0
  330.      * @access public
  331.      *
  332.      * @return array Controls settings.
  333.      */
  334.     public function get_controls_settings() {
  335.         return array_intersect_key( $this->get_settings(), $this->get_controls() );
  336.     }
  337.  
  338.     /**
  339.      * Add new control to stack.
  340.      *
  341.      * Register a single control to allow the user to set/update data.
  342.      *
  343.      * This method should be used inside `_register_controls()`.
  344.      *
  345.      * @since 1.4.0
  346.      * @access public
  347.      *
  348.      * @param string $id      Control ID.
  349.      * @param array  $args    Control arguments.
  350.      * @param array  $options Optional. Control options. Default is an empty array.
  351.      *
  352.      * @return bool True if control added, False otherwise.
  353.      */
  354.     public function add_control( $id, array $args, $options = [] ) {
  355.         $default_options = [
  356.             'overwrite' => false,
  357.             'position' => null,
  358.         ];
  359.  
  360.         $options = array_merge( $default_options, $options );
  361.  
  362.         if ( $options['position'] ) {
  363.             $this->start_injection( $options['position'] );
  364.         }
  365.  
  366.         if ( $this->injection_point ) {
  367.             $options['index'] = $this->injection_point['index']++;
  368.         }
  369.  
  370.         if ( empty( $args['type'] ) || ! in_array( $args['type'], [ Controls_Manager::SECTION, Controls_Manager::WP_WIDGET ], true ) ) {
  371.             $target_section_args = $this->current_section;
  372.  
  373.             $target_tab = $this->current_tab;
  374.  
  375.             if ( $this->injection_point ) {
  376.                 $target_section_args = $this->injection_point['section'];
  377.  
  378.                 if ( ! empty( $this->injection_point['tab'] ) ) {
  379.                     $target_tab = $this->injection_point['tab'];
  380.                 }
  381.             }
  382.  
  383.             if ( null !== $target_section_args ) {
  384.                 if ( ! empty( $args['section'] ) || ! empty( $args['tab'] ) ) {
  385.                     _doing_it_wrong( sprintf( '%s::%s', get_called_class(), __FUNCTION__ ), sprintf( 'Cannot redeclare control with `tab` or `section` args inside section "%s".', $id ), '1.0.0' );
  386.                 }
  387.  
  388.                 $args = array_replace_recursive( $target_section_args, $args );
  389.  
  390.                 if ( null !== $target_tab ) {
  391.                     $args = array_replace_recursive( $target_tab, $args );
  392.                 }
  393.             } elseif ( empty( $args['section'] ) && ( ! $options['overwrite'] || is_wp_error( Plugin::$instance->controls_manager->get_control_from_stack( $this->get_unique_name(), $id ) ) ) ) {
  394.                 wp_die( sprintf( '%s::%s: Cannot add a control outside of a section (use `start_controls_section`).', get_called_class(), __FUNCTION__ ) );
  395.             }
  396.         }
  397.  
  398.         if ( $options['position'] ) {
  399.             $this->end_injection();
  400.         }
  401.  
  402.         unset( $options['position'] );
  403.  
  404.         if ( $this->current_popover && ! $this->current_popover['initialized'] ) {
  405.             $args['popover'] = [
  406.                 'start' => true,
  407.             ];
  408.  
  409.             $this->current_popover['initialized'] = true;
  410.         }
  411.  
  412.         return Plugin::$instance->controls_manager->add_control_to_stack( $this, $id, $args, $options );
  413.     }
  414.  
  415.     /**
  416.      * Remove control from stack.
  417.      *
  418.      * Unregister an existing control and remove it from the stack.
  419.      *
  420.      * @since 1.4.0
  421.      * @access public
  422.      *
  423.      * @param string $control_id Control ID.
  424.      *
  425.      * @return bool|\WP_Error
  426.      */
  427.     public function remove_control( $control_id ) {
  428.         return Plugin::$instance->controls_manager->remove_control_from_stack( $this->get_unique_name(), $control_id );
  429.     }
  430.  
  431.     /**
  432.      * Update control in stack.
  433.      *
  434.      * Change the value of an existing control in the stack. When you add new
  435.      * control you set the `$args` parameter, this method allows you to update
  436.      * the arguments by passing new data.
  437.      *
  438.      * @since 1.4.0
  439.      * @since 1.8.1 New `$options` parameter added.
  440.      *
  441.      * @access public
  442.      *
  443.      * @param string $control_id Control ID.
  444.      * @param array  $args       Control arguments. Only the new fields you want
  445.      *                           to update.
  446.      * @param array  $options    Optional. Some additional options. Default is
  447.      *                           an empty array.
  448.      *
  449.      * @return bool
  450.      */
  451.     public function update_control( $control_id, array $args, array $options = [] ) {
  452.         $is_updated = Plugin::$instance->controls_manager->update_control_in_stack( $this, $control_id, $args, $options );
  453.  
  454.         if ( ! $is_updated ) {
  455.             return false;
  456.         }
  457.  
  458.         $control = $this->get_controls( $control_id );
  459.  
  460.         if ( Controls_Manager::SECTION === $control['type'] ) {
  461.             $section_args = $this->get_section_args( $control_id );
  462.  
  463.             $section_controls = $this->get_section_controls( $control_id );
  464.  
  465.             foreach ( $section_controls as $section_control_id => $section_control ) {
  466.                 $this->update_control( $section_control_id, $section_args, $options );
  467.             }
  468.         }
  469.  
  470.         return true;
  471.     }
  472.  
  473.     /**
  474.      * Get stack.
  475.      *
  476.      * Retrieve the stack of controls.
  477.      *
  478.      * @since 1.9.2
  479.      * @access public
  480.      *
  481.      * @return array Stack of controls.
  482.      */
  483.     public function get_stack() {
  484.         $stack = Plugin::$instance->controls_manager->get_element_stack( $this );
  485.  
  486.         if ( null === $stack ) {
  487.             $this->init_controls();
  488.  
  489.             return Plugin::$instance->controls_manager->get_element_stack( $this );
  490.         }
  491.  
  492.         return $stack;
  493.     }
  494.  
  495.     /**
  496.      * Get position information.
  497.      *
  498.      * Retrieve the position while injecting data, based on the element type.
  499.      *
  500.      * @since 1.7.0
  501.      * @access public
  502.      *
  503.      * @param array $position {
  504.      *     The injection position.
  505.      *
  506.      *     @type string $type     Injection type, either `control` or `section`.
  507.      *                            Default is `control`.
  508.      *     @type string $at       Where to inject. If `$type` is `control` accepts
  509.      *                            `before` and `after`. If `$type` is `section`
  510.      *                            accepts `start` and `end`. Default values based on
  511.      *                            the `type`.
  512.      *     @type string $of       Control/Section ID.
  513.      *     @type array  $fallback Fallback injection position. When the position is
  514.      *                            not found it will try to fetch the fallback
  515.      *                            position.
  516.      * }
  517.      *
  518.      * @return bool|array Position info.
  519.      */
  520.     final public function get_position_info( array $position ) {
  521.         $default_position = [
  522.             'type' => 'control',
  523.             'at' => 'after',
  524.         ];
  525.  
  526.         if ( ! empty( $position['type'] ) && 'section' === $position['type'] ) {
  527.             $default_position['at'] = 'end';
  528.         }
  529.  
  530.         $position = array_merge( $default_position, $position );
  531.  
  532.         if (
  533.             'control' === $position['type'] && in_array( $position['at'], [ 'start', 'end' ], true ) ||
  534.             'section' === $position['type'] && in_array( $position['at'], [ 'before', 'after' ], true )
  535.         ) {
  536.             _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' );
  537.  
  538.             return false;
  539.         }
  540.  
  541.         $target_control_index = $this->get_control_index( $position['of'] );
  542.  
  543.         if ( false === $target_control_index ) {
  544.             if ( ! empty( $position['fallback'] ) ) {
  545.                 return $this->get_position_info( $position['fallback'] );
  546.             }
  547.  
  548.             return false;
  549.         }
  550.  
  551.         $target_section_index = $target_control_index;
  552.  
  553.         $registered_controls = $this->get_controls();
  554.  
  555.         $controls_keys = array_keys( $registered_controls );
  556.  
  557.         while ( Controls_Manager::SECTION !== $registered_controls[ $controls_keys[ $target_section_index ] ]['type'] ) {
  558.             $target_section_index--;
  559.         }
  560.  
  561.         if ( 'section' === $position['type'] ) {
  562.             $target_control_index++;
  563.  
  564.             if ( 'end' === $position['at'] ) {
  565.                 while ( Controls_Manager::SECTION !== $registered_controls[ $controls_keys[ $target_control_index ] ]['type'] ) {
  566.                     if ( ++$target_control_index >= count( $registered_controls ) ) {
  567.                         break;
  568.                     }
  569.                 }
  570.             }
  571.         }
  572.  
  573.         $target_control = $registered_controls[ $controls_keys[ $target_control_index ] ];
  574.  
  575.         if ( 'after' === $position['at'] ) {
  576.             $target_control_index++;
  577.         }
  578.  
  579.         $section_id = $registered_controls[ $controls_keys[ $target_section_index ] ]['name'];
  580.  
  581.         $position_info = [
  582.             'index' => $target_control_index,
  583.             'section' => $this->get_section_args( $section_id ),
  584.         ];
  585.  
  586.         if ( ! empty( $target_control['tabs_wrapper'] ) ) {
  587.             $position_info['tab'] = [
  588.                 'tabs_wrapper' => $target_control['tabs_wrapper'],
  589.                 'inner_tab' => $target_control['inner_tab'],
  590.             ];
  591.         }
  592.  
  593.         return $position_info;
  594.     }
  595.  
  596.     /**
  597.      * Get control key.
  598.      *
  599.      * Retrieve the key of the control based on a given index of the control.
  600.      *
  601.      * @since 1.9.2
  602.      * @access public
  603.      *
  604.      * @param string $control_index Control index.
  605.      *
  606.      * @return int Control key.
  607.      */
  608.     final public function get_control_key( $control_index ) {
  609.         $registered_controls = $this->get_controls();
  610.  
  611.         $controls_keys = array_keys( $registered_controls );
  612.  
  613.         return $controls_keys[ $control_index ];
  614.     }
  615.  
  616.     /**
  617.      * Get control index.
  618.      *
  619.      * Retrieve the index of the control based on a given key of the control.
  620.      *
  621.      * @since 1.7.6
  622.      * @access public
  623.      *
  624.      * @param string $control_key Control key.
  625.      *
  626.      * @return false|int Control index.
  627.      */
  628.     final public function get_control_index( $control_key ) {
  629.         $controls = $this->get_controls();
  630.  
  631.         $controls_keys = array_keys( $controls );
  632.  
  633.         return array_search( $control_key, $controls_keys );
  634.     }
  635.  
  636.     /**
  637.      * Get section controls.
  638.      *
  639.      * Retrieve all controls under a specific section.
  640.      *
  641.      * @since 1.7.6
  642.      * @access public
  643.      *
  644.      * @param string $section_id Section ID.
  645.      *
  646.      * @return array Section controls
  647.      */
  648.     final public function get_section_controls( $section_id ) {
  649.         $section_index = $this->get_control_index( $section_id );
  650.  
  651.         $section_controls = [];
  652.  
  653.         $registered_controls = $this->get_controls();
  654.  
  655.         $controls_keys = array_keys( $registered_controls );
  656.  
  657.         while ( true ) {
  658.             $section_index++;
  659.  
  660.             if ( ! isset( $controls_keys[ $section_index ] ) ) {
  661.                 break;
  662.             }
  663.  
  664.             $control_key = $controls_keys[ $section_index ];
  665.  
  666.             if ( Controls_Manager::SECTION === $registered_controls[ $control_key ]['type'] ) {
  667.                 break;
  668.             }
  669.  
  670.             $section_controls[ $control_key ] = $registered_controls[ $control_key ];
  671.         };
  672.  
  673.         return $section_controls;
  674.     }
  675.  
  676.     /**
  677.      * Add new group control to stack.
  678.      *
  679.      * Register a set of related controls grouped together as a single unified
  680.      * control. For example grouping together like typography controls into a
  681.      * single, easy-to-use control.
  682.      *
  683.      * @since 1.4.0
  684.      * @access public
  685.      *
  686.      * @param string $group_name Group control name.
  687.      * @param array  $args       Group control arguments. Default is an empty array.
  688.      * @param array  $options    Optional. Group control options. Default is an
  689.      *                           empty array.
  690.      */
  691.     final public function add_group_control( $group_name, array $args = [], array $options = [] ) {
  692.         $group = Plugin::$instance->controls_manager->get_control_groups( $group_name );
  693.  
  694.         if ( ! $group ) {
  695.             wp_die( sprintf( '%s::%s: Group "%s" not found.', get_called_class(), __FUNCTION__, $group_name ) );
  696.         }
  697.  
  698.         $group->add_controls( $this, $args, $options );
  699.     }
  700.  
  701.     /**
  702.      * Get scheme controls.
  703.      *
  704.      * Retrieve all the controls that use schemes.
  705.      *
  706.      * @since 1.4.0
  707.      * @access public
  708.      *
  709.      * @return array Scheme controls.
  710.      */
  711.     final public function get_scheme_controls() {
  712.         $enabled_schemes = Schemes_Manager::get_enabled_schemes();
  713.  
  714.         return array_filter(
  715.             $this->get_controls(), function( $control ) use ( $enabled_schemes ) {
  716.                 return ( ! empty( $control['scheme'] ) && in_array( $control['scheme']['type'], $enabled_schemes ) );
  717.             }
  718.         );
  719.     }
  720.  
  721.     /**
  722.      * Get style controls.
  723.      *
  724.      * Retrieve style controls for all active controls or, when requested, from
  725.      * a specific set of controls.
  726.      *
  727.      * @since 1.4.0
  728.      * @since 2.0.9 Added the `settings` parameter.
  729.      * @access public
  730.      *
  731.      * @param array $controls Optional. Controls list. Default is null.
  732.      * @param array $settings Optional. Controls settings. Default is null.
  733.      *
  734.      * @return array Style controls.
  735.      */
  736.     final public function get_style_controls( array $controls = null, array $settings = null ) {
  737.         $controls = $this->get_active_controls( $controls, $settings );
  738.  
  739.         $style_controls = [];
  740.  
  741.         foreach ( $controls as $control_name => $control ) {
  742.             $control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
  743.  
  744.             if ( ! $control_obj instanceof Base_Data_Control ) {
  745.                 continue;
  746.             }
  747.  
  748.             $control = array_merge( $control_obj->get_settings(), $control );
  749.  
  750.             if ( Controls_Manager::REPEATER === $control['type'] ) {
  751.                 $style_fields = [];
  752.  
  753.                 foreach ( $this->get_settings( $control_name ) as $item ) {
  754.                     $style_fields[] = $this->get_style_controls( $control['fields'], $item );
  755.                 }
  756.  
  757.                 $control['style_fields'] = $style_fields;
  758.             }
  759.  
  760.             if ( ! empty( $control['selectors'] ) || ! empty( $control['dynamic'] ) || ! empty( $control['style_fields'] ) ) {
  761.                 $style_controls[ $control_name ] = $control;
  762.             }
  763.         }
  764.  
  765.         return $style_controls;
  766.     }
  767.  
  768.     /**
  769.      * Get class controls.
  770.      *
  771.      * Retrieve the controls that use the same prefix class from all the active
  772.      * controls
  773.      *
  774.      * @since 1.4.0
  775.      * @deprecated 2.1.0
  776.      * @access public
  777.      *
  778.      * @return array Class controls.
  779.      */
  780.     final public function get_class_controls() {
  781.         _deprecated_function( __METHOD__, '2.1.0' );
  782.  
  783.         return array_filter(
  784.             $this->get_active_controls(), function( $control ) {
  785.                 return ( isset( $control['prefix_class'] ) );
  786.             }
  787.         );
  788.     }
  789.  
  790.     /**
  791.      * Get tabs controls.
  792.      *
  793.      * Retrieve all the tabs assigned to the control.
  794.      *
  795.      * @since 1.4.0
  796.      * @access public
  797.      *
  798.      * @return array Tabs controls.
  799.      */
  800.     final public function get_tabs_controls() {
  801.         return $this->get_stack()['tabs'];
  802.     }
  803.  
  804.     /**
  805.      * Add new responsive control to stack.
  806.      *
  807.      * Register a set of controls to allow editing based on user screen size.
  808.      * This method registers three screen sizes: Desktop, Tablet and Mobile.
  809.      *
  810.      * @since 1.4.0
  811.      * @access public
  812.      *
  813.      * @param string $id      Responsive control ID.
  814.      * @param array  $args    Responsive control arguments.
  815.      * @param array  $options Optional. Responsive control options. Default is
  816.      *                        an empty array.
  817.      */
  818.     final public function add_responsive_control( $id, array $args, $options = [] ) {
  819.         $args['responsive'] = [];
  820.  
  821.         $devices = [
  822.             self::RESPONSIVE_DESKTOP,
  823.             self::RESPONSIVE_TABLET,
  824.             self::RESPONSIVE_MOBILE,
  825.         ];
  826.  
  827.         if ( isset( $args['devices'] ) ) {
  828.             $devices = array_intersect( $devices, $args['devices'] );
  829.  
  830.             $args['responsive']['devices'] = $devices;
  831.  
  832.             unset( $args['devices'] );
  833.         }
  834.  
  835.         if ( isset( $args['default'] ) ) {
  836.             $args['desktop_default'] = $args['default'];
  837.  
  838.             unset( $args['default'] );
  839.         }
  840.  
  841.         foreach ( $devices as $device_name ) {
  842.             $control_args = $args;
  843.  
  844.             if ( isset( $control_args['device_args'] ) ) {
  845.                 if ( ! empty( $control_args['device_args'][ $device_name ] ) ) {
  846.                     $control_args = array_merge( $control_args, $control_args['device_args'][ $device_name ] );
  847.                 }
  848.  
  849.                 unset( $control_args['device_args'] );
  850.             }
  851.  
  852.             if ( ! empty( $args['prefix_class'] ) ) {
  853.                 $device_to_replace = self::RESPONSIVE_DESKTOP === $device_name ? '' : '-' . $device_name;
  854.  
  855.                 $control_args['prefix_class'] = sprintf( $args['prefix_class'], $device_to_replace );
  856.             }
  857.  
  858.             $control_args['responsive']['max'] = $device_name;
  859.  
  860.             if ( isset( $control_args['min_affected_device'] ) ) {
  861.                 if ( ! empty( $control_args['min_affected_device'][ $device_name ] ) ) {
  862.                     $control_args['responsive']['min'] = $control_args['min_affected_device'][ $device_name ];
  863.                 }
  864.  
  865.                 unset( $control_args['min_affected_device'] );
  866.             }
  867.  
  868.             if ( isset( $control_args[ $device_name . '_default' ] ) ) {
  869.                 $control_args['default'] = $control_args[ $device_name . '_default' ];
  870.             }
  871.  
  872.             unset( $control_args['desktop_default'] );
  873.             unset( $control_args['tablet_default'] );
  874.             unset( $control_args['mobile_default'] );
  875.  
  876.             $id_suffix = self::RESPONSIVE_DESKTOP === $device_name ? '' : '_' . $device_name;
  877.  
  878.             if ( ! empty( $options['overwrite'] ) ) {
  879.                 $this->update_control( $id . $id_suffix, $control_args, [
  880.                     'recursive' => ! empty( $options['recursive'] ),
  881.                 ] );
  882.             } else {
  883.                 $this->add_control( $id . $id_suffix, $control_args, $options );
  884.             }
  885.         }
  886.     }
  887.  
  888.     /**
  889.      * Update responsive control in stack.
  890.      *
  891.      * Change the value of an existing responsive control in the stack. When you
  892.      * add new control you set the `$args` parameter, this method allows you to
  893.      * update the arguments by passing new data.
  894.      *
  895.      * @since 1.4.0
  896.      * @access public
  897.      *
  898.      * @param string $id      Responsive control ID.
  899.      * @param array  $args    Responsive control arguments.
  900.      * @param array  $options Optional. Additional options.
  901.      */
  902.     final public function update_responsive_control( $id, array $args, array $options = [] ) {
  903.         $this->add_responsive_control( $id, $args, [
  904.             'overwrite' => true,
  905.             'recursive' => ! empty( $options['recursive'] ),
  906.         ] );
  907.     }
  908.  
  909.     /**
  910.      * Remove responsive control from stack.
  911.      *
  912.      * Unregister an existing responsive control and remove it from the stack.
  913.      *
  914.      * @since 1.4.0
  915.      * @access public
  916.      *
  917.      * @param string $id Responsive control ID.
  918.      */
  919.     final public function remove_responsive_control( $id ) {
  920.         $devices = [
  921.             self::RESPONSIVE_DESKTOP,
  922.             self::RESPONSIVE_TABLET,
  923.             self::RESPONSIVE_MOBILE,
  924.         ];
  925.  
  926.         foreach ( $devices as $device_name ) {
  927.             $id_suffix = self::RESPONSIVE_DESKTOP === $device_name ? '' : '_' . $device_name;
  928.  
  929.             $this->remove_control( $id . $id_suffix );
  930.         }
  931.     }
  932.  
  933.     /**
  934.      * Get class name.
  935.      *
  936.      * Retrieve the name of the current class.
  937.      *
  938.      * @since 1.4.0
  939.      * @access public
  940.      *
  941.      * @return string Class name.
  942.      */
  943.     final public function get_class_name() {
  944.         return get_called_class();
  945.     }
  946.  
  947.     /**
  948.      * Get the config.
  949.      *
  950.      * Retrieve the config or, if non set, use the initial config.
  951.      *
  952.      * @since 1.4.0
  953.      * @access public
  954.      *
  955.      * @return array|null The config.
  956.      */
  957.     final public function get_config() {
  958.         if ( null === $this->config ) {
  959.             $this->config = $this->_get_initial_config();
  960.         }
  961.  
  962.         return $this->config;
  963.     }
  964.  
  965.     /**
  966.      * Get frontend settings keys.
  967.      *
  968.      * Retrieve settings keys for all frontend controls.
  969.      *
  970.      * @since 1.6.0
  971.      * @access public
  972.      *
  973.      * @return array Settings keys for each control.
  974.      */
  975.     final public function get_frontend_settings_keys() {
  976.         $controls = [];
  977.  
  978.         foreach ( $this->get_controls() as $control ) {
  979.             if ( ! empty( $control['frontend_available'] ) ) {
  980.                 $controls[] = $control['name'];
  981.             }
  982.         }
  983.  
  984.         return $controls;
  985.     }
  986.  
  987.     /**
  988.      * Get controls pointer index.
  989.      *
  990.      * Retrieve pointer index where the next control should be added.
  991.      *
  992.      * While using injection point, it will return the injection point index.
  993.      * Otherwise index of the last control plus one.
  994.      *
  995.      * @since 1.9.2
  996.      * @access public
  997.      *
  998.      * @return int Controls pointer index.
  999.      */
  1000.     public function get_pointer_index() {
  1001.         if ( null !== $this->injection_point ) {
  1002.             return $this->injection_point['index'];
  1003.         }
  1004.  
  1005.         return count( $this->get_controls() );
  1006.     }
  1007.  
  1008.     /**
  1009.      * Get the raw data.
  1010.      *
  1011.      * Retrieve all the items or, when requested, a specific item.
  1012.      *
  1013.      * @since 1.4.0
  1014.      * @access public
  1015.      *
  1016.      * @param string $item Optional. The requested item. Default is null.
  1017.      *
  1018.      * @return mixed The raw data.
  1019.      */
  1020.     public function get_data( $item = null ) {
  1021.         if ( ! $this->settings_sanitized && ( ! $item || 'settings' === $item ) ) {
  1022.             $this->data['settings'] = $this->sanitize_settings( $this->data['settings'] );
  1023.  
  1024.             $this->settings_sanitized = true;
  1025.         }
  1026.  
  1027.         return self::get_items( $this->data, $item );
  1028.     }
  1029.  
  1030.     /**
  1031.      * @since 2.0.14
  1032.      * @access public
  1033.      */
  1034.     public function get_parsed_dynamic_settings( $setting = null ) {
  1035.         if ( null === $this->parsed_dynamic_settings ) {
  1036.             $this->parsed_dynamic_settings = $this->parse_dynamic_settings( $this->get_settings() );
  1037.         }
  1038.  
  1039.         return self::get_items( $this->parsed_dynamic_settings, $setting );
  1040.     }
  1041.  
  1042.     /**
  1043.      * Get active settings.
  1044.      *
  1045.      * Retrieve the settings from all the active controls.
  1046.      *
  1047.      * @since 1.4.0
  1048.      * @since 2.1.0 Added the `controls` and the `settings` parameters.
  1049.      * @access public
  1050.      *
  1051.      * @param array $controls Optional. An array of controls. Default is null.
  1052.      * @param array $settings Optional. Controls settings. Default is null.
  1053.      *
  1054.      * @return array Active settings.
  1055.      */
  1056.     public function get_active_settings( $settings = null, $controls = null ) {
  1057.         $is_first_request = ! $settings && ! $this->active_settings;
  1058.  
  1059.         if ( ! $settings ) {
  1060.             if ( $this->active_settings ) {
  1061.                 return $this->active_settings;
  1062.             }
  1063.  
  1064.             $settings = $this->get_controls_settings();
  1065.  
  1066.             $controls = $this->get_controls();
  1067.         }
  1068.  
  1069.         $active_settings = [];
  1070.  
  1071.         foreach ( $settings as $setting_key => $setting ) {
  1072.             if ( ! isset( $controls[ $setting_key ] ) ) {
  1073.                 $active_settings[ $setting_key ] = $setting;
  1074.  
  1075.                 continue;
  1076.             }
  1077.  
  1078.             $control = $controls[ $setting_key ];
  1079.  
  1080.             if ( $this->is_control_visible( $control, $settings ) ) {
  1081.                 if ( Controls_Manager::REPEATER === $control['type'] ) {
  1082.                     foreach ( $setting as & $item ) {
  1083.                         $item = $this->get_active_settings( $item, $control['fields'] );
  1084.                     }
  1085.                 }
  1086.  
  1087.                 $active_settings[ $setting_key ] = $setting;
  1088.             } else {
  1089.                 $active_settings[ $setting_key ] = null;
  1090.             }
  1091.         }
  1092.  
  1093.         if ( $is_first_request ) {
  1094.             $this->active_settings = $active_settings;
  1095.         }
  1096.  
  1097.         return $active_settings;
  1098.     }
  1099.  
  1100.     /**
  1101.      * Get settings for display.
  1102.      *
  1103.      * Retrieve all the settings or, when requested, a specific setting for display.
  1104.      *
  1105.      * Unlike `get_settings()` method, this method retrieves only active settings
  1106.      * that passed all the conditions, rendered all the shortcodes and all the dynamic
  1107.      * tags.
  1108.      *
  1109.      * @since 2.0.0
  1110.      * @access public
  1111.      *
  1112.      * @param string $setting_key Optional. The key of the requested setting.
  1113.      *                            Default is null.
  1114.      *
  1115.      * @return mixed The settings.
  1116.      */
  1117.     public function get_settings_for_display( $setting_key = null ) {
  1118.         if ( ! $this->parsed_active_settings ) {
  1119.             $this->parsed_active_settings = $this->get_active_settings( $this->get_parsed_dynamic_settings(), $this->get_controls() );
  1120.         }
  1121.  
  1122.         return self::get_items( $this->parsed_active_settings, $setting_key );
  1123.     }
  1124.  
  1125.     /**
  1126.      * Parse dynamic settings.
  1127.      *
  1128.      * Retrieve the settings with rendered dynamic tags.
  1129.      *
  1130.      * @since 2.0.0
  1131.      * @access public
  1132.      *
  1133.      * @param array $settings     Optional. The requested setting. Default is null.
  1134.      * @param array $controls     Optional. The controls array. Default is null.
  1135.      * @param array $all_settings Optional. All the settings. Default is null.
  1136.      *
  1137.      * @return array The settings with rendered dynamic tags.
  1138.      */
  1139.     public function parse_dynamic_settings( $settings, $controls = null, $all_settings = null ) {
  1140.         if ( null === $all_settings ) {
  1141.             $all_settings = $this->get_settings();
  1142.         }
  1143.  
  1144.         if ( null === $controls ) {
  1145.             $controls = $this->get_controls();
  1146.         }
  1147.  
  1148.         foreach ( $controls as $control ) {
  1149.             $control_name = $control['name'];
  1150.             $control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
  1151.  
  1152.             if ( ! $control_obj instanceof Base_Data_Control ) {
  1153.                 continue;
  1154.             }
  1155.  
  1156.             if ( 'repeater' === $control_obj->get_type() ) {
  1157.                 foreach ( $settings[ $control_name ] as & $field ) {
  1158.                     $field = $this->parse_dynamic_settings( $field, $control['fields'], $field );
  1159.                 }
  1160.  
  1161.                 continue;
  1162.             }
  1163.  
  1164.             if ( empty( $control['dynamic'] ) || ! isset( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
  1165.                 continue;
  1166.             }
  1167.  
  1168.             $dynamic_settings = array_merge( $control_obj->get_settings( 'dynamic' ), $control['dynamic'] );
  1169.  
  1170.             if ( ! empty( $dynamic_settings['active'] ) && ! empty( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
  1171.                 $parsed_value = $control_obj->parse_tags( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ], $dynamic_settings );
  1172.  
  1173.                 $dynamic_property = ! empty( $dynamic_settings['property'] ) ? $dynamic_settings['property'] : null;
  1174.  
  1175.                 if ( $dynamic_property ) {
  1176.                     $settings[ $control_name ][ $dynamic_property ] = $parsed_value;
  1177.                 } else {
  1178.                     $settings[ $control_name ] = $parsed_value;
  1179.                 }
  1180.             }
  1181.         }
  1182.  
  1183.         return $settings;
  1184.     }
  1185.  
  1186.     /**
  1187.      * Get frontend settings.
  1188.      *
  1189.      * Retrieve the settings for all frontend controls.
  1190.      *
  1191.      * @since 1.6.0
  1192.      * @access public
  1193.      *
  1194.      * @return array Frontend settings.
  1195.      */
  1196.     public function get_frontend_settings() {
  1197.         $frontend_settings = array_intersect_key( $this->get_active_settings(), array_flip( $this->get_frontend_settings_keys() ) );
  1198.  
  1199.         foreach ( $frontend_settings as $key => $setting ) {
  1200.             if ( in_array( $setting, [ null, '' ], true ) ) {
  1201.                 unset( $frontend_settings[ $key ] );
  1202.             }
  1203.         }
  1204.  
  1205.         return $frontend_settings;
  1206.     }
  1207.  
  1208.     /**
  1209.      * Filter controls settings.
  1210.      *
  1211.      * Receives controls, settings and a callback function to filter the settings by
  1212.      * and returns filtered settings.
  1213.      *
  1214.      * @since 1.5.0
  1215.      * @access public
  1216.      *
  1217.      * @param callable $callback The callback function.
  1218.      * @param array    $settings Optional. Control settings. Default is an empty
  1219.      *                           array.
  1220.      * @param array    $controls Optional. Controls list. Default is an empty
  1221.      *                           array.
  1222.      *
  1223.      * @return array Filtered settings.
  1224.      */
  1225.     public function filter_controls_settings( callable $callback, array $settings = [], array $controls = [] ) {
  1226.         if ( ! $settings ) {
  1227.             $settings = $this->get_settings();
  1228.         }
  1229.  
  1230.         if ( ! $controls ) {
  1231.             $controls = $this->get_controls();
  1232.         }
  1233.  
  1234.         return array_reduce(
  1235.             array_keys( $settings ), function( $filtered_settings, $setting_key ) use ( $controls, $settings, $callback ) {
  1236.                 if ( isset( $controls[ $setting_key ] ) ) {
  1237.                     $result = $callback( $settings[ $setting_key ], $controls[ $setting_key ] );
  1238.  
  1239.                     if ( null !== $result ) {
  1240.                         $filtered_settings[ $setting_key ] = $result;
  1241.                     }
  1242.                 }
  1243.  
  1244.                 return $filtered_settings;
  1245.             }, []
  1246.         );
  1247.     }
  1248.  
  1249.     /**
  1250.      * Whether the control is visible or not.
  1251.      *
  1252.      * Used to determine whether the control is visible or not.
  1253.      *
  1254.      * @since 1.4.0
  1255.      * @access public
  1256.      *
  1257.      * @param array $control The control.
  1258.      * @param array $values  Optional. Condition values. Default is null.
  1259.      *
  1260.      * @return bool Whether the control is visible.
  1261.      */
  1262.     public function is_control_visible( $control, $values = null ) {
  1263.         if ( null === $values ) {
  1264.             $values = $this->get_settings();
  1265.         }
  1266.  
  1267.         if ( ! empty( $control['conditions'] ) ) {
  1268.             return Conditions::check( $control['conditions'], $values );
  1269.         }
  1270.  
  1271.         if ( empty( $control['condition'] ) ) {
  1272.             return true;
  1273.         }
  1274.  
  1275.         foreach ( $control['condition'] as $condition_key => $condition_value ) {
  1276.             preg_match( '/([a-z_\-0-9]+)(?:\[([a-z_]+)])?(!?)$/i', $condition_key, $condition_key_parts );
  1277.  
  1278.             $pure_condition_key = $condition_key_parts[1];
  1279.             $condition_sub_key = $condition_key_parts[2];
  1280.             $is_negative_condition = ! ! $condition_key_parts[3];
  1281.  
  1282.             if ( ! isset( $values[ $pure_condition_key ] ) || null === $values[ $pure_condition_key ] ) {
  1283.                 return false;
  1284.             }
  1285.  
  1286.             $instance_value = $values[ $pure_condition_key ];
  1287.  
  1288.             if ( $condition_sub_key && is_array( $instance_value ) ) {
  1289.                 if ( ! isset( $instance_value[ $condition_sub_key ] ) ) {
  1290.                     return false;
  1291.                 }
  1292.  
  1293.                 $instance_value = $instance_value[ $condition_sub_key ];
  1294.             }
  1295.  
  1296.             /**
  1297.              * If the $condition_value is a non empty array - check if the $condition_value contains the $instance_value,
  1298.              * If the $instance_value is a non empty array - check if the $instance_value contains the $condition_value
  1299.              * otherwise check if they are equal. ( and give the ability to check if the value is an empty array )
  1300.              */
  1301.             if ( is_array( $condition_value ) && ! empty( $condition_value ) ) {
  1302.                 $is_contains = in_array( $instance_value, $condition_value, true );
  1303.             } elseif ( is_array( $instance_value ) && ! empty( $instance_value ) ) {
  1304.                 $is_contains = in_array( $condition_value, $instance_value, true );
  1305.             } else {
  1306.                 $is_contains = $instance_value === $condition_value;
  1307.             }
  1308.  
  1309.             if ( $is_negative_condition && $is_contains || ! $is_negative_condition && ! $is_contains ) {
  1310.                 return false;
  1311.             }
  1312.         }
  1313.  
  1314.         return true;
  1315.     }
  1316.  
  1317.     /**
  1318.      * Start controls section.
  1319.      *
  1320.      * Used to add a new section of controls. When you use this method, all the
  1321.      * registered controls from this point will be assigned to this section,
  1322.      * until you close the section using `end_controls_section()` method.
  1323.      *
  1324.      * This method should be used inside `_register_controls()`.
  1325.      *
  1326.      * @since 1.4.0
  1327.      * @access public
  1328.      *
  1329.      * @param string $section_id Section ID.
  1330.      * @param array  $args       Section arguments Optional.
  1331.      */
  1332.     public function start_controls_section( $section_id, array $args = [] ) {
  1333.         $section_name = $this->get_name();
  1334.  
  1335.         /**
  1336.          * Before section start.
  1337.          *
  1338.          * Fires before Elementor section starts in the editor panel.
  1339.          *
  1340.          * @since 1.4.0
  1341.          *
  1342.          * @param Controls_Stack $this       The control.
  1343.          * @param string         $section_id Section ID.
  1344.          * @param array          $args       Section arguments.
  1345.          */
  1346.         do_action( 'elementor/element/before_section_start', $this, $section_id, $args );
  1347.  
  1348.         /**
  1349.          * Before section start.
  1350.          *
  1351.          * Fires before Elementor section starts in the editor panel.
  1352.          *
  1353.          * The dynamic portions of the hook name, `$section_name` and `$section_id`, refers to the section name and section ID, respectively.
  1354.          *
  1355.          * @since 1.4.0
  1356.          *
  1357.          * @param Controls_Stack $this The control.
  1358.          * @param array          $args Section arguments.
  1359.          */
  1360.         do_action( "elementor/element/{$section_name}/{$section_id}/before_section_start", $this, $args );
  1361.  
  1362.         $args['type'] = Controls_Manager::SECTION;
  1363.  
  1364.         $this->add_control( $section_id, $args );
  1365.  
  1366.         if ( null !== $this->current_section ) {
  1367.             wp_die( sprintf( 'Elementor: You can\'t start a section before the end of the previous section "%s".', $this->current_section['section'] ) ); // XSS ok.
  1368.         }
  1369.  
  1370.         $this->current_section = $this->get_section_args( $section_id );
  1371.  
  1372.         if ( $this->injection_point ) {
  1373.             $this->injection_point['section'] = $this->current_section;
  1374.         }
  1375.  
  1376.         /**
  1377.          * After section start.
  1378.          *
  1379.          * Fires after Elementor section starts in the editor panel.
  1380.          *
  1381.          * @since 1.4.0
  1382.          *
  1383.          * @param Controls_Stack $this       The control.
  1384.          * @param string         $section_id Section ID.
  1385.          * @param array          $args       Section arguments.
  1386.          */
  1387.         do_action( 'elementor/element/after_section_start', $this, $section_id, $args );
  1388.  
  1389.         /**
  1390.          * After section start.
  1391.          *
  1392.          * Fires after Elementor section starts in the editor panel.
  1393.          *
  1394.          * The dynamic portions of the hook name, `$section_name` and `$section_id`, refers to the section name and section ID, respectively.
  1395.          *
  1396.          * @since 1.4.0
  1397.          *
  1398.          * @param Controls_Stack $this The control.
  1399.          * @param array          $args Section arguments.
  1400.          */
  1401.         do_action( "elementor/element/{$section_name}/{$section_id}/after_section_start", $this, $args );
  1402.     }
  1403.  
  1404.     /**
  1405.      * End controls section.
  1406.      *
  1407.      * Used to close an existing open controls section. When you use this method
  1408.      * it stops adding new controls to this section.
  1409.      *
  1410.      * This method should be used inside `_register_controls()`.
  1411.      *
  1412.      * @since 1.4.0
  1413.      * @access public
  1414.      */
  1415.     public function end_controls_section() {
  1416.         $stack_name = $this->get_name();
  1417.  
  1418.         // Save the current section for the action.
  1419.         $current_section = $this->current_section;
  1420.         $section_id = $current_section['section'];
  1421.         $args = [
  1422.             'tab' => $current_section['tab'],
  1423.         ];
  1424.  
  1425.         /**
  1426.          * Before section end.
  1427.          *
  1428.          * Fires before Elementor section ends in the editor panel.
  1429.          *
  1430.          * @since 1.4.0
  1431.          *
  1432.          * @param Controls_Stack $this       The control.
  1433.          * @param string         $section_id Section ID.
  1434.          * @param array          $args       Section arguments.
  1435.          */
  1436.         do_action( 'elementor/element/before_section_end', $this, $section_id, $args );
  1437.  
  1438.         /**
  1439.          * Before section end.
  1440.          *
  1441.          * Fires before Elementor section ends in the editor panel.
  1442.          *
  1443.          * The dynamic portions of the hook name, `$stack_name` and `$section_id`, refers to the stack name and section ID, respectively.
  1444.          *
  1445.          * @since 1.4.0
  1446.          *
  1447.          * @param Controls_Stack $this The control.
  1448.          * @param array          $args Section arguments.
  1449.          */
  1450.         do_action( "elementor/element/{$stack_name}/{$section_id}/before_section_end", $this, $args );
  1451.  
  1452.         $this->current_section = null;
  1453.  
  1454.         /**
  1455.          * After section end.
  1456.          *
  1457.          * Fires after Elementor section ends in the editor panel.
  1458.          *
  1459.          * @since 1.4.0
  1460.          *
  1461.          * @param Controls_Stack $this       The control.
  1462.          * @param string         $section_id Section ID.
  1463.          * @param array          $args       Section arguments.
  1464.          */
  1465.         do_action( 'elementor/element/after_section_end', $this, $section_id, $args );
  1466.  
  1467.         /**
  1468.          * After section end.
  1469.          *
  1470.          * Fires after Elementor section ends in the editor panel.
  1471.          *
  1472.          * The dynamic portions of the hook name, `$stack_name` and `$section_id`, refers to the section name and section ID, respectively.
  1473.          *
  1474.          * @since 1.4.0
  1475.          *
  1476.          * @param Controls_Stack $this The control.
  1477.          * @param array          $args Section arguments.
  1478.          */
  1479.         do_action( "elementor/element/{$stack_name}/{$section_id}/after_section_end", $this, $args );
  1480.     }
  1481.  
  1482.     /**
  1483.      * Start controls tabs.
  1484.      *
  1485.      * Used to add a new set of tabs inside a section. You should use this
  1486.      * method before adding new individual tabs using `start_controls_tab()`.
  1487.      * Each tab added after this point will be assigned to this group of tabs,
  1488.      * until you close it using `end_controls_tabs()` method.
  1489.      *
  1490.      * This method should be used inside `_register_controls()`.
  1491.      *
  1492.      * @since 1.4.0
  1493.      * @access public
  1494.      *
  1495.      * @param string $tabs_id Tabs ID.
  1496.      * @param array  $args    Tabs arguments.
  1497.      */
  1498.     public function start_controls_tabs( $tabs_id, array $args = [] ) {
  1499.         if ( null !== $this->current_tab ) {
  1500.             wp_die( sprintf( 'Elementor: You can\'t start tabs before the end of the previous tabs "%s".', $this->current_tab['tabs_wrapper'] ) ); // XSS ok.
  1501.         }
  1502.  
  1503.         $args['type'] = Controls_Manager::TABS;
  1504.  
  1505.         $this->add_control( $tabs_id, $args );
  1506.  
  1507.         $this->current_tab = [
  1508.             'tabs_wrapper' => $tabs_id,
  1509.         ];
  1510.  
  1511.         foreach ( [ 'condition', 'conditions' ] as $key ) {
  1512.             if ( ! empty( $args[ $key ] ) ) {
  1513.                 $this->current_tab[ $key ] = $args[ $key ];
  1514.             }
  1515.         }
  1516.  
  1517.         if ( $this->injection_point ) {
  1518.             $this->injection_point['tab'] = $this->current_tab;
  1519.         }
  1520.     }
  1521.  
  1522.     /**
  1523.      * End controls tabs.
  1524.      *
  1525.      * Used to close an existing open controls tabs. When you use this method it
  1526.      * stops adding new controls to this tabs.
  1527.      *
  1528.      * This method should be used inside `_register_controls()`.
  1529.      *
  1530.      * @since 1.4.0
  1531.      * @access public
  1532.      */
  1533.     public function end_controls_tabs() {
  1534.         $this->current_tab = null;
  1535.     }
  1536.  
  1537.     /**
  1538.      * Start controls tab.
  1539.      *
  1540.      * Used to add a new tab inside a group of tabs. Use this method before
  1541.      * adding new individual tabs using `start_controls_tab()`.
  1542.      * Each tab added after this point will be assigned to this group of tabs,
  1543.      * until you close it using `end_controls_tab()` method.
  1544.      *
  1545.      * This method should be used inside `_register_controls()`.
  1546.      *
  1547.      * @since 1.4.0
  1548.      * @access public
  1549.      *
  1550.      * @param string $tab_id Tab ID.
  1551.      * @param array  $args   Tab arguments.
  1552.      */
  1553.     public function start_controls_tab( $tab_id, $args ) {
  1554.         if ( ! empty( $this->current_tab['inner_tab'] ) ) {
  1555.             wp_die( sprintf( 'Elementor: You can\'t start a tab before the end of the previous tab "%s".', $this->current_tab['inner_tab'] ) ); // XSS ok.
  1556.         }
  1557.  
  1558.         $args['type'] = Controls_Manager::TAB;
  1559.         $args['tabs_wrapper'] = $this->current_tab['tabs_wrapper'];
  1560.  
  1561.         $this->add_control( $tab_id, $args );
  1562.  
  1563.         $this->current_tab['inner_tab'] = $tab_id;
  1564.  
  1565.         if ( $this->injection_point ) {
  1566.             $this->injection_point['tab']['inner_tab'] = $this->current_tab['inner_tab'];
  1567.         }
  1568.     }
  1569.  
  1570.     /**
  1571.      * End controls tab.
  1572.      *
  1573.      * Used to close an existing open controls tab. When you use this method it
  1574.      * stops adding new controls to this tab.
  1575.      *
  1576.      * This method should be used inside `_register_controls()`.
  1577.      *
  1578.      * @since 1.4.0
  1579.      * @access public
  1580.      */
  1581.     public function end_controls_tab() {
  1582.         unset( $this->current_tab['inner_tab'] );
  1583.     }
  1584.  
  1585.     /**
  1586.      * Start popover.
  1587.      *
  1588.      * Used to add a new set of controls in a popover. When you use this method,
  1589.      * all the registered controls from this point will be assigned to this
  1590.      * popover, until you close the popover using `end_popover()` method.
  1591.      *
  1592.      * This method should be used inside `_register_controls()`.
  1593.      *
  1594.      * @since 1.9.0
  1595.      * @access public
  1596.      */
  1597.     final public function start_popover() {
  1598.         $this->current_popover = [
  1599.             'initialized' => false,
  1600.         ];
  1601.     }
  1602.  
  1603.     /**
  1604.      * End popover.
  1605.      *
  1606.      * Used to close an existing open popover. When you use this method it stops
  1607.      * adding new controls to this popover.
  1608.      *
  1609.      * This method should be used inside `_register_controls()`.
  1610.      *
  1611.      * @since 1.9.0
  1612.      * @access public
  1613.      */
  1614.     final public function end_popover() {
  1615.         $this->current_popover = null;
  1616.  
  1617.         $last_control_key = $this->get_control_key( $this->get_pointer_index() - 1 );
  1618.  
  1619.         $args = [
  1620.             'popover' => [
  1621.                 'end' => true,
  1622.             ],
  1623.         ];
  1624.  
  1625.         $options = [
  1626.             'recursive' => true,
  1627.         ];
  1628.  
  1629.         $this->update_control( $last_control_key, $args, $options );
  1630.     }
  1631.  
  1632.     /**
  1633.      * Print element template.
  1634.      *
  1635.      * Used to generate the element template on the editor.
  1636.      *
  1637.      * @since 2.0.0
  1638.      * @access public
  1639.      */
  1640.     public function print_template() {
  1641.         ob_start();
  1642.  
  1643.         $this->_content_template();
  1644.  
  1645.         $template_content = ob_get_clean();
  1646.  
  1647.         $element_type = $this->get_type();
  1648.  
  1649.         /**
  1650.          * Template content.
  1651.          *
  1652.          * Filters the controls stack template content before it's printed in the editor.
  1653.          *
  1654.          * The dynamic portion of the hook name, `$element_type`, refers to the element type.
  1655.          *
  1656.          * @since 1.0.0
  1657.          *
  1658.          * @param string         $content_template The controls stack template in the editor.
  1659.          * @param Controls_Stack $this             The controls stack.
  1660.          */
  1661.         $template_content = apply_filters( "elementor/{$element_type}/print_template", $template_content, $this );
  1662.  
  1663.         if ( empty( $template_content ) ) {
  1664.             return;
  1665.         }
  1666.         ?>
  1667.         <script type="text/html" id="tmpl-elementor-<?php echo esc_attr( $this->get_name() ); ?>-content">
  1668.             <?php $this->print_template_content( $template_content ); ?>
  1669.         </script>
  1670.         <?php
  1671.     }
  1672.  
  1673.     /**
  1674.      * Start injection.
  1675.      *
  1676.      * Used to inject controls and sections to a specific position in the stack.
  1677.      *
  1678.      * When you use this method, all the registered controls and sections will
  1679.      * be injected to a specific position in the stack, until you stop the
  1680.      * injection using `end_injection()` method.
  1681.      *
  1682.      * @since 1.7.1
  1683.      * @access public
  1684.      *
  1685.      * @param array $position {
  1686.      *     The position where to start the injection.
  1687.      *
  1688.      *     @type string $type Injection type, either `control` or `section`.
  1689.      *                        Default is `control`.
  1690.      *     @type string $at   Where to inject. If `$type` is `control` accepts
  1691.      *                        `before` and `after`. If `$type` is `section`
  1692.      *                        accepts `start` and `end`. Default values based on
  1693.      *                        the `type`.
  1694.      *     @type string $of   Control/Section ID.
  1695.      * }
  1696.      */
  1697.     final public function start_injection( array $position ) {
  1698.         if ( $this->injection_point ) {
  1699.             wp_die( 'A controls injection is already opened. Please close current injection before starting a new one (use `end_injection`).' );
  1700.         }
  1701.  
  1702.         $this->injection_point = $this->get_position_info( $position );
  1703.     }
  1704.  
  1705.     /**
  1706.      * End injection.
  1707.      *
  1708.      * Used to close an existing opened injection point.
  1709.      *
  1710.      * When you use this method it stops adding new controls and sections to
  1711.      * this point and continue to add controls to the regular position in the
  1712.      * stack.
  1713.      *
  1714.      * @since 1.7.1
  1715.      * @access public
  1716.      */
  1717.     final public function end_injection() {
  1718.         $this->injection_point = null;
  1719.     }
  1720.  
  1721.     /**
  1722.      * Get injection point.
  1723.      *
  1724.      * Retrieve the injection point in the stack where new controls and sections
  1725.      * will be inserted.
  1726.      *
  1727.      * @since 1.9.2
  1728.      * @access public
  1729.      *
  1730.      * @return array|null An array when an injection point is defined, null
  1731.      *                    otherwise.
  1732.      */
  1733.     final public function get_injection_point() {
  1734.         return $this->injection_point;
  1735.     }
  1736.  
  1737.     /**
  1738.      * Register controls.
  1739.      *
  1740.      * Used to add new controls to any element type. For example, external
  1741.      * developers use this method to register controls in a widget.
  1742.      *
  1743.      * Should be inherited and register new controls using `add_control()`,
  1744.      * `add_responsive_control()` and `add_group_control()`, inside control
  1745.      * wrappers like `start_controls_section()`, `start_controls_tabs()` and
  1746.      * `start_controls_tab()`.
  1747.      *
  1748.      * @since 1.4.0
  1749.      * @access protected
  1750.      */
  1751.     protected function _register_controls() {}
  1752.  
  1753.     /**
  1754.      * Get default data.
  1755.      *
  1756.      * Retrieve the default data. Used to reset the data on initialization.
  1757.      *
  1758.      * @since 1.4.0
  1759.      * @access protected
  1760.      *
  1761.      * @return array Default data.
  1762.      */
  1763.     protected function get_default_data() {
  1764.         return [
  1765.             'id' => 0,
  1766.             'settings' => [],
  1767.         ];
  1768.     }
  1769.  
  1770.     /**
  1771.      * @since 2.3.0
  1772.      * @access protected
  1773.      */
  1774.     protected function get_init_settings() {
  1775.         $settings = $this->get_data( 'settings' );
  1776.  
  1777.         foreach ( $this->get_controls() as $control ) {
  1778.             $control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
  1779.  
  1780.             if ( ! $control_obj instanceof Base_Data_Control ) {
  1781.                 continue;
  1782.             }
  1783.  
  1784.             $control = array_merge_recursive( $control_obj->get_settings(), $control );
  1785.  
  1786.             $settings[ $control['name'] ] = $control_obj->get_value( $control, $settings );
  1787.         }
  1788.  
  1789.         return $settings;
  1790.     }
  1791.  
  1792.     /**
  1793.      * Get parsed settings.
  1794.      *
  1795.      * Retrieve the parsed settings for all the controls that represent them.
  1796.      * The parser set default values and process the settings.
  1797.      *
  1798.      * Classes that extend `Controls_Stack` can add new process to the settings
  1799.      * parser.
  1800.      *
  1801.      * @since 1.4.0
  1802.      * @deprecated 2.3.0 Use `Controls_Stack::get_init_settings()` instead
  1803.      * @access protected
  1804.      *
  1805.      * @return array Parsed settings.
  1806.      */
  1807.     protected function _get_parsed_settings() {
  1808.         _deprecated_function( __METHOD__, '2.3.0', __CLASS__ . '::get_init_settings()' );
  1809.  
  1810.         return $this->get_init_settings();
  1811.     }
  1812.  
  1813.     /**
  1814.      * Get initial config.
  1815.      *
  1816.      * Retrieve the current element initial configuration - controls list and
  1817.      * the tabs assigned to the control.
  1818.      *
  1819.      * @since 1.4.0
  1820.      * @access protected
  1821.      *
  1822.      * @return array The initial config.
  1823.      */
  1824.     protected function _get_initial_config() {
  1825.         return [
  1826.             'controls' => $this->get_controls(),
  1827.         ];
  1828.     }
  1829.  
  1830.     /**
  1831.      * Get section arguments.
  1832.      *
  1833.      * Retrieve the section arguments based on section ID.
  1834.      *
  1835.      * @since 1.4.0
  1836.      * @access protected
  1837.      *
  1838.      * @param string $section_id Section ID.
  1839.      *
  1840.      * @return array Section arguments.
  1841.      */
  1842.     protected function get_section_args( $section_id ) {
  1843.         $section_control = $this->get_controls( $section_id );
  1844.  
  1845.         $section_args_keys = [ 'tab', 'condition' ];
  1846.  
  1847.         $args = array_intersect_key( $section_control, array_flip( $section_args_keys ) );
  1848.  
  1849.         $args['section'] = $section_id;
  1850.  
  1851.         return $args;
  1852.     }
  1853.  
  1854.     /**
  1855.      * Render element.
  1856.      *
  1857.      * Generates the final HTML on the frontend.
  1858.      *
  1859.      * @since 2.0.0
  1860.      * @access protected
  1861.      */
  1862.     protected function render() {}
  1863.  
  1864.     /**
  1865.      * Print content template.
  1866.      *
  1867.      * Used to generate the content template on the editor, using a
  1868.      * Backbone JavaScript template.
  1869.      *
  1870.      * @access protected
  1871.      * @since 2.0.0
  1872.      *
  1873.      * @param string $template_content Template content.
  1874.      */
  1875.     protected function print_template_content( $template_content ) {
  1876.         echo $template_content;
  1877.     }
  1878.  
  1879.     /**
  1880.      * Render element output in the editor.
  1881.      *
  1882.      * Used to generate the live preview, using a Backbone JavaScript template.
  1883.      *
  1884.      * @since 2.0.0
  1885.      * @access protected
  1886.      */
  1887.     protected function _content_template() {}
  1888.  
  1889.     /**
  1890.      * Initialize controls.
  1891.      *
  1892.      * Register the all controls added by `_register_controls()`.
  1893.      *
  1894.      * @since 2.0.0
  1895.      * @access protected
  1896.      */
  1897.     protected function init_controls() {
  1898.         Plugin::$instance->controls_manager->open_stack( $this );
  1899.  
  1900.         $this->_register_controls();
  1901.     }
  1902.  
  1903.     /**
  1904.      * Initialize the class.
  1905.      *
  1906.      * Set the raw data, the ID and the parsed settings.
  1907.      *
  1908.      * @since 1.4.0
  1909.      * @access protected
  1910.      *
  1911.      * @param array $data Initial data.
  1912.      */
  1913.     protected function _init( $data ) {
  1914.         $this->data = array_merge( $this->get_default_data(), $data );
  1915.  
  1916.         $this->id = $data['id'];
  1917.     }
  1918.  
  1919.     /**
  1920.      * Sanitize initial data.
  1921.      *
  1922.      * Performs settings cleaning and sanitization.
  1923.      *
  1924.      * @since 2.1.5
  1925.      * @access private
  1926.      *
  1927.      * @param array $settings Settings to sanitize.
  1928.      * @param array $controls Optional. An array of controls. Default is an
  1929.      *                        empty array.
  1930.      *
  1931.      * @return array Sanitized settings.
  1932.      */
  1933.     private function sanitize_settings( array $settings, array $controls = [] ) {
  1934.         if ( ! $controls ) {
  1935.             $controls = $this->get_controls();
  1936.         }
  1937.  
  1938.         foreach ( $controls as $control ) {
  1939.             if ( 'repeater' === $control['type'] ) {
  1940.                 if ( empty( $settings[ $control['name'] ] ) ) {
  1941.                     continue;
  1942.                 }
  1943.  
  1944.                 foreach ( $settings[ $control['name'] ] as $index => $repeater_row_data ) {
  1945.                     $sanitized_row_data = $this->sanitize_settings( $repeater_row_data, $control['fields'] );
  1946.  
  1947.                     $settings[ $control['name'] ][ $index ] = $sanitized_row_data;
  1948.                 }
  1949.  
  1950.                 continue;
  1951.             }
  1952.  
  1953.             $is_dynamic = isset( $settings[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ] );
  1954.  
  1955.             if ( ! $is_dynamic ) {
  1956.                 continue;
  1957.             }
  1958.  
  1959.             $value_to_check = $settings[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ];
  1960.  
  1961.             $tag_text_data = Plugin::$instance->dynamic_tags->tag_text_to_tag_data( $value_to_check );
  1962.  
  1963.             if ( ! Plugin::$instance->dynamic_tags->get_tag_info( $tag_text_data['name'] ) ) {
  1964.                 unset( $settings[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ] );
  1965.             }
  1966.         }
  1967.  
  1968.         return $settings;
  1969.     }
  1970.  
  1971.     /**
  1972.      * Controls stack constructor.
  1973.      *
  1974.      * Initializing the control stack class using `$data`. The `$data` is required
  1975.      * for a normal instance. It is optional only for internal `type instance`.
  1976.      *
  1977.      * @since 1.4.0
  1978.      * @access public
  1979.      *
  1980.      * @param array $data Optional. Control stack data. Default is an empty array.
  1981.      */
  1982.     public function __construct( array $data = [] ) {
  1983.         if ( $data ) {
  1984.             $this->_init( $data );
  1985.         }
  1986.     }
  1987. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top