Advertisement
Guest User

Untitled

a guest
Jul 16th, 2019
206
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 52.70 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement