settings.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. <?php
  2. namespace Elementor;
  3. use Elementor\Core\Responsive\Responsive;
  4. use Elementor\Core\Settings\General\Manager as General_Settings_Manager;
  5. use Elementor\Core\Settings\Manager;
  6. if ( ! defined( 'ABSPATH' ) ) {
  7. exit; // Exit if accessed directly.
  8. }
  9. /**
  10. * Elementor "Settings" page in WordPress Dashboard.
  11. *
  12. * Elementor settings page handler class responsible for creating and displaying
  13. * Elementor "Settings" page in WordPress dashboard.
  14. *
  15. * @since 1.0.0
  16. */
  17. class Settings extends Settings_Page {
  18. /**
  19. * Settings page ID for Elementor settings.
  20. */
  21. const PAGE_ID = 'elementor';
  22. /**
  23. * Go Pro menu priority.
  24. */
  25. const MENU_PRIORITY_GO_PRO = 502;
  26. /**
  27. * Settings page field for update time.
  28. */
  29. const UPDATE_TIME_FIELD = '_elementor_settings_update_time';
  30. /**
  31. * Settings page general tab slug.
  32. */
  33. const TAB_GENERAL = 'general';
  34. /**
  35. * Settings page style tab slug.
  36. */
  37. const TAB_STYLE = 'style';
  38. /**
  39. * Settings page integrations tab slug.
  40. */
  41. const TAB_INTEGRATIONS = 'integrations';
  42. /**
  43. * Settings page advanced tab slug.
  44. */
  45. const TAB_ADVANCED = 'advanced';
  46. /**
  47. * Register admin menu.
  48. *
  49. * Add new Elementor Settings admin menu.
  50. *
  51. * Fired by `admin_menu` action.
  52. *
  53. * @since 1.0.0
  54. * @access public
  55. */
  56. public function register_admin_menu() {
  57. add_menu_page(
  58. __( 'Elementor', 'elementor' ),
  59. __( 'Elementor', 'elementor' ),
  60. 'manage_options',
  61. self::PAGE_ID,
  62. [ $this, 'display_settings_page' ],
  63. '',
  64. 99
  65. );
  66. }
  67. /**
  68. * Register Elementor Pro sub-menu.
  69. *
  70. * Add new Elementor Pro sub-menu under the main Elementor menu.
  71. *
  72. * Fired by `admin_menu` action.
  73. *
  74. * @since 1.0.0
  75. * @access public
  76. */
  77. public function register_pro_menu() {
  78. add_submenu_page(
  79. self::PAGE_ID,
  80. __( 'Custom Fonts', 'elementor' ),
  81. __( 'Custom Fonts', 'elementor' ),
  82. 'manage_options',
  83. 'elementor_custom_fonts',
  84. [ $this, 'elementor_custom_fonts' ]
  85. );
  86. add_submenu_page(
  87. self::PAGE_ID,
  88. '',
  89. '<span class="dashicons dashicons-star-filled" style="font-size: 17px"></span> ' . __( 'Go Pro', 'elementor' ),
  90. 'manage_options',
  91. 'go_elementor_pro',
  92. [ $this, 'handle_external_redirects' ]
  93. );
  94. }
  95. /**
  96. * Register Elementor knowledge base sub-menu.
  97. *
  98. * Add new Elementor knowledge base sub-menu under the main Elementor menu.
  99. *
  100. * Fired by `admin_menu` action.
  101. *
  102. * @since 2.0.3
  103. * @access public
  104. */
  105. public function register_knowledge_base_menu() {
  106. add_submenu_page(
  107. self::PAGE_ID,
  108. '',
  109. __( 'Getting Started', 'elementor' ),
  110. 'manage_options',
  111. 'elementor-getting-started',
  112. [ $this, 'elementor_getting_started' ]
  113. );
  114. add_submenu_page(
  115. self::PAGE_ID,
  116. '',
  117. __( 'Knowledge Base', 'elementor' ),
  118. 'manage_options',
  119. 'go_knowledge_base_site',
  120. [ $this, 'handle_external_redirects' ]
  121. );
  122. }
  123. /**
  124. * Go Elementor Pro.
  125. *
  126. * Redirect the Elementor Pro page the clicking the Elementor Pro menu link.
  127. *
  128. * Fired by `admin_init` action.
  129. *
  130. * @since 2.0.3
  131. * @access public
  132. */
  133. public function handle_external_redirects() {
  134. if ( empty( $_GET['page'] ) ) {
  135. return;
  136. }
  137. if ( 'go_elementor_pro' === $_GET['page'] ) {
  138. wp_redirect( Utils::get_pro_link( 'https://elementor.com/pro/?utm_source=wp-menu&utm_campaign=gopro&utm_medium=wp-dash' ) );
  139. die;
  140. }
  141. if ( 'go_knowledge_base_site' === $_GET['page'] ) {
  142. wp_redirect( 'https://go.elementor.com/docs-admin-menu/' );
  143. die;
  144. }
  145. }
  146. /**
  147. * Display settings page.
  148. *
  149. * Output the content for the getting started page.
  150. *
  151. * @since 2.2.0
  152. * @access public
  153. */
  154. public function elementor_getting_started() {
  155. if ( User::is_current_user_can_edit_post_type( 'page' ) ) {
  156. $create_new_label = __( 'Create Your First Page', 'elementor' );
  157. $create_new_cpt = 'page';
  158. } elseif ( User::is_current_user_can_edit_post_type( 'post' ) ) {
  159. $create_new_label = __( 'Create Your First Post', 'elementor' );
  160. $create_new_cpt = 'post';
  161. }
  162. ?>
  163. <div class="wrap">
  164. <div class="e-getting-started">
  165. <div class="e-getting-started__box postbox">
  166. <div class="e-getting-started__header">
  167. <div class="e-getting-started__title">
  168. <div class="e-logo-wrapper"><i class="eicon-elementor"></i></div>
  169. <?php echo __( 'Getting Started', 'elementor' ); ?>
  170. </div>
  171. <a class="e-getting-started__skip" href="<?php echo esc_url( admin_url() ); ?>">
  172. <i class="eicon-close" aria-hidden="true" title="<?php esc_attr_e( 'Skip', 'elementor' ); ?>"></i>
  173. <span class="elementor-screen-only"><?php echo __( 'Skip', 'elementor' ); ?></span>
  174. </a>
  175. </div>
  176. <div class="e-getting-started__content">
  177. <div class="e-getting-started__content--narrow">
  178. <h2><?php echo __( 'Welcome to Elementor', 'elementor' ); ?></h2>
  179. <p><?php echo __( 'We recommend you watch this 2 minute getting started video, and then try the editor yourself by dragging and dropping elements to create your first page.', 'elementor' ); ?></p>
  180. </div>
  181. <div class="e-getting-started__video">
  182. <iframe width="620" height="350" src="https://www.youtube-nocookie.com/embed/-TPpwuB6dnI?rel=0&amp;controls=1&amp;showinfo=0&amp;modestbranding=1" frameborder="0" allowfullscreen></iframe>
  183. </div>
  184. <div class="e-getting-started__actions e-getting-started__content--narrow">
  185. <?php if ( ! empty( $create_new_cpt ) ) : ?>
  186. <a href="<?php echo esc_url( Utils::get_create_new_post_url( $create_new_cpt ) ); ?>" class="button button-primary button-hero"><?php echo esc_html( $create_new_label ); ?></a>
  187. <?php endif; ?>
  188. <a href="https://go.elementor.com/getting-started/" target="_blank" class="button button-secondary button-hero"><?php echo __( 'Read the Full Article', 'elementor' ); ?></a>
  189. </div>
  190. </div>
  191. </div>
  192. </div>
  193. </div><!-- /.wrap -->
  194. <?php
  195. }
  196. /**
  197. * Display settings page.
  198. *
  199. * Output the content for the custom fonts page.
  200. *
  201. * @since 2.0.0
  202. * @access public
  203. */
  204. public function elementor_custom_fonts() {
  205. ?>
  206. <div class="wrap">
  207. <div class="elementor-blank_state">
  208. <i class="eicon-nerd-chuckle"></i>
  209. <h2><?php echo __( 'Add Your Custom Fonts', 'elementor' ); ?></h2>
  210. <p><?php echo __( 'Custom Fonts allows you to add your self-hosted fonts and use them on your Elementor projects to create a unique brand language.', 'elementor' ); ?></p>
  211. <a class="elementor-button elementor-button-default elementor-button-go-pro" target="_blank" href="<?php echo Utils::get_pro_link( 'https://elementor.com/pro/?utm_source=wp-custom-fonts&utm_campaign=gopro&utm_medium=wp-dash' ); ?>"><?php echo __( 'Go Pro', 'elementor' ); ?></a>
  212. </div>
  213. </div><!-- /.wrap -->
  214. <?php
  215. }
  216. /**
  217. * On admin init.
  218. *
  219. * Preform actions on WordPress admin initialization.
  220. *
  221. * Fired by `admin_init` action.
  222. *
  223. * @since 2.0.0
  224. * @access public
  225. */
  226. public function on_admin_init() {
  227. $this->handle_external_redirects();
  228. // Save general settings in one list for a future usage
  229. $this->handle_general_settings_update();
  230. $this->maybe_remove_all_admin_notices();
  231. }
  232. /**
  233. * Change "Settings" menu name.
  234. *
  235. * Update the name of the Settings admin menu from "Elementor" to "Settings".
  236. *
  237. * Fired by `admin_menu` action.
  238. *
  239. * @since 1.0.0
  240. * @access public
  241. */
  242. public function admin_menu_change_name() {
  243. global $submenu;
  244. if ( isset( $submenu['elementor'] ) ) {
  245. // @codingStandardsIgnoreStart
  246. $submenu['elementor'][0][0] = __( 'Settings', 'elementor' );
  247. $hold_menu_data = $submenu['elementor'][0];
  248. $submenu['elementor'][0] = $submenu['elementor'][1];
  249. $submenu['elementor'][1] = $hold_menu_data;
  250. // @codingStandardsIgnoreEnd
  251. }
  252. }
  253. /**
  254. * Update CSS print method.
  255. *
  256. * Clear post CSS cache.
  257. *
  258. * Fired by `add_option_elementor_css_print_method` and
  259. * `update_option_elementor_css_print_method` actions.
  260. *
  261. * @since 1.7.5
  262. * @access public
  263. */
  264. public function update_css_print_method() {
  265. Plugin::$instance->files_manager->clear_cache();
  266. }
  267. /**
  268. * Create tabs.
  269. *
  270. * Return the settings page tabs, sections and fields.
  271. *
  272. * @since 1.5.0
  273. * @access protected
  274. *
  275. * @return array An array with the settings page tabs, sections and fields.
  276. */
  277. protected function create_tabs() {
  278. $validations_class_name = __NAMESPACE__ . '\Settings_Validations';
  279. $default_breakpoints = Responsive::get_default_breakpoints();
  280. return [
  281. self::TAB_GENERAL => [
  282. 'label' => __( 'General', 'elementor' ),
  283. 'sections' => [
  284. 'general' => [
  285. 'fields' => [
  286. self::UPDATE_TIME_FIELD => [
  287. 'full_field_id' => self::UPDATE_TIME_FIELD,
  288. 'field_args' => [
  289. 'type' => 'hidden',
  290. ],
  291. 'setting_args' => [
  292. 'sanitize_callback' => 'time',
  293. ],
  294. ],
  295. 'cpt_support' => [
  296. 'label' => __( 'Post Types', 'elementor' ),
  297. 'field_args' => [
  298. 'type' => 'checkbox_list_cpt',
  299. 'std' => [ 'page', 'post' ],
  300. 'exclude' => [ 'attachment', 'elementor_library' ],
  301. ],
  302. 'setting_args' => [ $validations_class_name, 'checkbox_list' ],
  303. ],
  304. 'disable_color_schemes' => [
  305. 'label' => __( 'Disable Default Colors', 'elementor' ),
  306. 'field_args' => [
  307. 'type' => 'checkbox',
  308. 'value' => 'yes',
  309. 'sub_desc' => __( 'Checking this box will disable Elementor\'s Default Colors, and make Elementor inherit the colors from your theme.', 'elementor' ),
  310. ],
  311. ],
  312. 'disable_typography_schemes' => [
  313. 'label' => __( 'Disable Default Fonts', 'elementor' ),
  314. 'field_args' => [
  315. 'type' => 'checkbox',
  316. 'value' => 'yes',
  317. 'sub_desc' => __( 'Checking this box will disable Elementor\'s Default Fonts, and make Elementor inherit the fonts from your theme.', 'elementor' ),
  318. ],
  319. ],
  320. ],
  321. ],
  322. 'usage' => [
  323. 'label' => __( 'Improve Elementor', 'elementor' ),
  324. 'fields' => [
  325. 'allow_tracking' => [
  326. 'label' => __( 'Usage Data Tracking', 'elementor' ),
  327. 'field_args' => [
  328. 'type' => 'checkbox',
  329. 'value' => 'yes',
  330. 'default' => '',
  331. 'sub_desc' => __( 'Opt-in to our anonymous plugin data collection and to updates. We guarantee no sensitive data is collected.', 'elementor' ) . sprintf( ' <a href="%1$s" target="_blank">%2$s</a>', 'https://go.elementor.com/usage-data-tracking/', __( 'Learn more.', 'elementor' ) ),
  332. ],
  333. 'setting_args' => [ __NAMESPACE__ . '\Tracker', 'check_for_settings_optin' ],
  334. ],
  335. ],
  336. ],
  337. ],
  338. ],
  339. self::TAB_STYLE => [
  340. 'label' => __( 'Style', 'elementor' ),
  341. 'sections' => [
  342. 'style' => [
  343. 'fields' => [
  344. 'default_generic_fonts' => [
  345. 'label' => __( 'Default Generic Fonts', 'elementor' ),
  346. 'field_args' => [
  347. 'type' => 'text',
  348. 'std' => 'Sans-serif',
  349. 'class' => 'medium-text',
  350. 'desc' => __( 'The list of fonts used if the chosen font is not available.', 'elementor' ),
  351. ],
  352. ],
  353. 'container_width' => [
  354. 'label' => __( 'Content Width', 'elementor' ),
  355. 'field_args' => [
  356. 'type' => 'number',
  357. 'attributes' => [
  358. 'placeholder' => '1140',
  359. 'class' => 'medium-text',
  360. ],
  361. 'sub_desc' => 'px',
  362. 'desc' => __( 'Sets the default width of the content area (Default: 1140)', 'elementor' ),
  363. ],
  364. ],
  365. 'space_between_widgets' => [
  366. 'label' => __( 'Space Between Widgets', 'elementor' ),
  367. 'field_args' => [
  368. 'type' => 'number',
  369. 'attributes' => [
  370. 'placeholder' => '20',
  371. 'class' => 'medium-text',
  372. ],
  373. 'sub_desc' => 'px',
  374. 'desc' => __( 'Sets the default space between widgets (Default: 20)', 'elementor' ),
  375. ],
  376. ],
  377. 'stretched_section_container' => [
  378. 'label' => __( 'Stretched Section Fit To', 'elementor' ),
  379. 'field_args' => [
  380. 'type' => 'text',
  381. 'attributes' => [
  382. 'placeholder' => 'body',
  383. 'class' => 'medium-text',
  384. ],
  385. 'desc' => __( 'Enter parent element selector to which stretched sections will fit to (e.g. #primary / .wrapper / main etc). Leave blank to fit to page width.', 'elementor' ),
  386. ],
  387. ],
  388. 'page_title_selector' => [
  389. 'label' => __( 'Page Title Selector', 'elementor' ),
  390. 'field_args' => [
  391. 'type' => 'text',
  392. 'attributes' => [
  393. 'placeholder' => 'h1.entry-title',
  394. 'class' => 'medium-text',
  395. ],
  396. 'desc' => __( 'Elementor lets you hide the page title. This works for themes that have "h1.entry-title" selector. If your theme\'s selector is different, please enter it above.', 'elementor' ),
  397. ],
  398. ],
  399. 'viewport_lg' => [
  400. 'label' => __( 'Tablet Breakpoint', 'elementor' ),
  401. 'field_args' => [
  402. 'type' => 'number',
  403. 'attributes' => [
  404. 'placeholder' => $default_breakpoints['lg'],
  405. 'min' => $default_breakpoints['md'] + 1,
  406. 'max' => $default_breakpoints['xl'] - 1,
  407. 'class' => 'medium-text',
  408. ],
  409. 'sub_desc' => 'px',
  410. /* translators: %d: Breakpoint value */
  411. 'desc' => sprintf( __( 'Sets the breakpoint between desktop and tablet devices. Below this breakpoint tablet layout will appear (Default: %dpx).', 'elementor' ), $default_breakpoints['lg'] ),
  412. ],
  413. ],
  414. 'viewport_md' => [
  415. 'label' => __( 'Mobile Breakpoint', 'elementor' ),
  416. 'field_args' => [
  417. 'type' => 'number',
  418. 'attributes' => [
  419. 'placeholder' => $default_breakpoints['md'],
  420. 'min' => $default_breakpoints['sm'] + 1,
  421. 'max' => $default_breakpoints['lg'] - 1,
  422. 'class' => 'medium-text',
  423. ],
  424. 'sub_desc' => 'px',
  425. /* translators: %d: Breakpoint value */
  426. 'desc' => sprintf( __( 'Sets the breakpoint between tablet and mobile devices. Below this breakpoint mobile layout will appear (Default: %dpx).', 'elementor' ), $default_breakpoints['md'] ),
  427. ],
  428. ],
  429. 'global_image_lightbox' => [
  430. 'label' => __( 'Image Lightbox', 'elementor' ),
  431. 'field_args' => [
  432. 'type' => 'checkbox',
  433. 'value' => 'yes',
  434. 'std' => 'yes',
  435. 'sub_desc' => __( 'Open all image links in a lightbox popup window. The lightbox will automatically work on any link that leads to an image file.', 'elementor' ),
  436. 'desc' => __( 'You can customize the lightbox design by going to: Top-left hamburger icon > Global Settings > Lightbox.', 'elementor' ),
  437. ],
  438. ],
  439. ],
  440. ],
  441. ],
  442. ],
  443. self::TAB_INTEGRATIONS => [
  444. 'label' => __( 'Integrations', 'elementor' ),
  445. 'sections' => [],
  446. ],
  447. self::TAB_ADVANCED => [
  448. 'label' => __( 'Advanced', 'elementor' ),
  449. 'sections' => [
  450. 'advanced' => [
  451. 'fields' => [
  452. 'css_print_method' => [
  453. 'label' => __( 'CSS Print Method', 'elementor' ),
  454. 'field_args' => [
  455. 'class' => 'elementor_css_print_method',
  456. 'type' => 'select',
  457. 'options' => [
  458. 'external' => __( 'External File', 'elementor' ),
  459. 'internal' => __( 'Internal Embedding', 'elementor' ),
  460. ],
  461. 'desc' => '<div class="elementor-css-print-method-description" data-value="external" style="display: none">' .
  462. __( 'Use external CSS files for all generated stylesheets. Choose this setting for better performance (recommended).', 'elementor' ) .
  463. '</div>' .
  464. '<div class="elementor-css-print-method-description" data-value="internal" style="display: none">' .
  465. __( 'Use internal CSS that is embedded in the head of the page. For troubleshooting server configuration conflicts and managing development environments.', 'elementor' ) .
  466. '</div>',
  467. ],
  468. ],
  469. 'editor_break_lines' => [
  470. 'label' => __( 'Switch Editor Loader Method', 'elementor' ),
  471. 'field_args' => [
  472. 'type' => 'select',
  473. 'options' => [
  474. '' => __( 'Disable', 'elementor' ),
  475. 1 => __( 'Enable', 'elementor' ),
  476. ],
  477. 'desc' => __( 'For troubleshooting server configuration conflicts.', 'elementor' ),
  478. ],
  479. ],
  480. 'edit_buttons' => [
  481. 'label' => __( 'Editing Handles', 'elementor' ),
  482. 'field_args' => [
  483. 'type' => 'select',
  484. 'std' => '',
  485. 'options' => [
  486. '' => __( 'Hide', 'elementor' ),
  487. 'on' => __( 'Show', 'elementor' ),
  488. ],
  489. 'desc' => __( 'Show editing handles when hovering over the element edit button', 'elementor' ),
  490. ],
  491. ],
  492. ],
  493. ],
  494. ],
  495. ],
  496. ];
  497. }
  498. /**
  499. * Get settings page title.
  500. *
  501. * Retrieve the title for the settings page.
  502. *
  503. * @since 1.5.0
  504. * @access protected
  505. *
  506. * @return string Settings page title.
  507. */
  508. protected function get_page_title() {
  509. return __( 'Elementor', 'elementor' );
  510. }
  511. /**
  512. * Handle general settings update.
  513. *
  514. * Save general settings in one list for a future usage.
  515. *
  516. * @since 2.0.0
  517. * @access private
  518. */
  519. private function handle_general_settings_update() {
  520. if ( ! empty( $_POST['option_page'] ) && self::PAGE_ID === $_POST['option_page'] && ! empty( $_POST['action'] ) && 'update' === $_POST['action'] ) {
  521. check_admin_referer( 'elementor-options' );
  522. $saved_general_settings = get_option( General_Settings_Manager::META_KEY );
  523. if ( ! $saved_general_settings ) {
  524. $saved_general_settings = [];
  525. }
  526. $general_settings = Manager::get_settings_managers( 'general' )->get_model()->get_settings();
  527. foreach ( $general_settings as $setting_key => $setting ) {
  528. if ( ! empty( $_POST[ $setting_key ] ) ) {
  529. $pure_setting_key = str_replace( 'elementor_', '', $setting_key );
  530. $saved_general_settings[ $pure_setting_key ] = $_POST[ $setting_key ];
  531. }
  532. }
  533. update_option( General_Settings_Manager::META_KEY, $saved_general_settings );
  534. }
  535. }
  536. private function maybe_remove_all_admin_notices() {
  537. $elementor_pages = [
  538. 'elementor-getting-started',
  539. 'elementor-role-manager',
  540. 'elementor_custom_fonts',
  541. 'elementor-license',
  542. ];
  543. if ( empty( $_GET['page'] ) || ! in_array( $_GET['page'], $elementor_pages, true ) ) {
  544. return;
  545. }
  546. remove_all_actions( 'admin_notices' );
  547. }
  548. /**
  549. * Settings page constructor.
  550. *
  551. * Initializing Elementor "Settings" page.
  552. *
  553. * @since 1.0.0
  554. * @access public
  555. */
  556. public function __construct() {
  557. parent::__construct();
  558. add_action( 'admin_init', [ $this, 'on_admin_init' ] );
  559. add_action( 'admin_menu', [ $this, 'register_admin_menu' ], 20 );
  560. add_action( 'admin_menu', [ $this, 'admin_menu_change_name' ], 200 );
  561. add_action( 'admin_menu', [ $this, 'register_pro_menu' ], self::MENU_PRIORITY_GO_PRO );
  562. add_action( 'admin_menu', [ $this, 'register_knowledge_base_menu' ], 501 );
  563. // Clear CSS Meta after change print method.
  564. add_action( 'add_option_elementor_css_print_method', [ $this, 'update_css_print_method' ] );
  565. add_action( 'update_option_elementor_css_print_method', [ $this, 'update_css_print_method' ] );
  566. foreach ( Responsive::get_editable_breakpoints() as $breakpoint_key => $breakpoint ) {
  567. foreach ( [ 'add', 'update' ] as $action ) {
  568. add_action( "{$action}_option_elementor_viewport_{$breakpoint_key}", [ 'Elementor\Responsive', 'compile_stylesheet_templates' ] );
  569. }
  570. }
  571. }
  572. }