settings-page.php (10185B)
1 <?php 2 namespace Elementor; 3 4 if ( ! defined( 'ABSPATH' ) ) { 5 exit; // Exit if accessed directly. 6 } 7 8 /** 9 * Elementor settings page. 10 * 11 * An abstract class that provides the needed properties and methods to handle 12 * WordPress dashboard settings pages in inheriting classes. 13 * 14 * @since 1.0.0 15 * @abstract 16 */ 17 abstract class Settings_Page { 18 19 /** 20 * Settings page ID. 21 */ 22 const PAGE_ID = ''; 23 24 /** 25 * Tabs. 26 * 27 * Holds the settings page tabs, sections and fields. 28 * 29 * @access private 30 * 31 * @var array 32 */ 33 private $tabs; 34 35 /** 36 * Create tabs. 37 * 38 * Return the settings page tabs, sections and fields. 39 * 40 * @since 1.5.0 41 * @access protected 42 * @abstract 43 */ 44 abstract protected function create_tabs(); 45 46 /** 47 * Get settings page title. 48 * 49 * Retrieve the title for the settings page. 50 * 51 * @since 1.5.0 52 * @access protected 53 * @abstract 54 */ 55 abstract protected function get_page_title(); 56 57 /** 58 * Get settings page URL. 59 * 60 * Retrieve the URL of the settings page. 61 * 62 * @since 1.5.0 63 * @access public 64 * @static 65 * 66 * @return string Settings page URL. 67 */ 68 final public static function get_url() { 69 return admin_url( 'admin.php?page=' . static::PAGE_ID ); 70 } 71 72 /** 73 * Settings page constructor. 74 * 75 * Initializing Elementor settings page. 76 * 77 * @since 1.5.0 78 * @access public 79 */ 80 public function __construct() { 81 // PHPCS - The user data is not used. 82 if ( ! empty( $_POST['option_page'] ) && static::PAGE_ID === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing 83 add_action( 'admin_init', [ $this, 'register_settings_fields' ] ); 84 } 85 } 86 87 /** 88 * Get tabs. 89 * 90 * Retrieve the settings page tabs, sections and fields. 91 * 92 * @since 1.5.0 93 * @access public 94 * 95 * @return array Settings page tabs, sections and fields. 96 */ 97 final public function get_tabs() { 98 $this->ensure_tabs(); 99 100 return $this->tabs; 101 } 102 103 /** 104 * Add tab. 105 * 106 * Register a new tab to a settings page. 107 * 108 * @since 1.5.0 109 * @access public 110 * 111 * @param string $tab_id Tab ID. 112 * @param array $tab_args Optional. Tab arguments. Default is an empty array. 113 */ 114 final public function add_tab( $tab_id, array $tab_args = [] ) { 115 $this->ensure_tabs(); 116 117 if ( isset( $this->tabs[ $tab_id ] ) ) { 118 // Don't override an existing tab 119 return; 120 } 121 122 if ( ! isset( $tab_args['sections'] ) ) { 123 $tab_args['sections'] = []; 124 } 125 126 $this->tabs[ $tab_id ] = $tab_args; 127 } 128 129 /** 130 * Add section. 131 * 132 * Register a new section to a tab. 133 * 134 * @since 1.5.0 135 * @access public 136 * 137 * @param string $tab_id Tab ID. 138 * @param string $section_id Section ID. 139 * @param array $section_args Optional. Section arguments. Default is an 140 * empty array. 141 */ 142 final public function add_section( $tab_id, $section_id, array $section_args = [] ) { 143 $this->ensure_tabs(); 144 145 if ( ! isset( $this->tabs[ $tab_id ] ) ) { 146 // If the requested tab doesn't exists, use the first tab 147 $tab_id = key( $this->tabs ); 148 } 149 150 if ( isset( $this->tabs[ $tab_id ]['sections'][ $section_id ] ) ) { 151 // Don't override an existing section 152 return; 153 } 154 155 if ( ! isset( $section_args['fields'] ) ) { 156 $section_args['fields'] = []; 157 } 158 159 $this->tabs[ $tab_id ]['sections'][ $section_id ] = $section_args; 160 } 161 162 /** 163 * Add field. 164 * 165 * Register a new field to a section. 166 * 167 * @since 1.5.0 168 * @access public 169 * 170 * @param string $tab_id Tab ID. 171 * @param string $section_id Section ID. 172 * @param string $field_id Field ID. 173 * @param array $field_args Field arguments. 174 */ 175 final public function add_field( $tab_id, $section_id, $field_id, array $field_args ) { 176 $this->ensure_tabs(); 177 178 if ( ! isset( $this->tabs[ $tab_id ] ) ) { 179 // If the requested tab doesn't exists, use the first tab 180 $tab_id = key( $this->tabs ); 181 } 182 183 if ( ! isset( $this->tabs[ $tab_id ]['sections'][ $section_id ] ) ) { 184 // If the requested section doesn't exists, use the first section 185 $section_id = key( $this->tabs[ $tab_id ]['sections'] ); 186 } 187 188 if ( isset( $this->tabs[ $tab_id ]['sections'][ $section_id ]['fields'][ $field_id ] ) ) { 189 // Don't override an existing field 190 return; 191 } 192 193 $this->tabs[ $tab_id ]['sections'][ $section_id ]['fields'][ $field_id ] = $field_args; 194 } 195 196 /** 197 * Add fields. 198 * 199 * Register multiple fields to a section. 200 * 201 * @since 1.5.0 202 * @access public 203 * 204 * @param string $tab_id Tab ID. 205 * @param string $section_id Section ID. 206 * @param array $fields { 207 * An array of fields. 208 * 209 * @type string $field_id Field ID. 210 * @type array $field_args Field arguments. 211 * } 212 */ 213 final public function add_fields( $tab_id, $section_id, array $fields ) { 214 foreach ( $fields as $field_id => $field_args ) { 215 $this->add_field( $tab_id, $section_id, $field_id, $field_args ); 216 } 217 } 218 219 /** 220 * Register settings fields. 221 * 222 * In each tab register his inner sections, and in each section register his 223 * inner fields. 224 * 225 * @since 1.5.0 226 * @access public 227 */ 228 final public function register_settings_fields() { 229 $controls_class_name = __NAMESPACE__ . '\Settings_Controls'; 230 231 $tabs = $this->get_tabs(); 232 233 foreach ( $tabs as $tab_id => $tab ) { 234 235 foreach ( $tab['sections'] as $section_id => $section ) { 236 $full_section_id = 'elementor_' . $section_id . '_section'; 237 238 $label = isset( $section['label'] ) ? $section['label'] : ''; 239 240 $section_callback = isset( $section['callback'] ) ? $section['callback'] : '__return_empty_string'; 241 242 add_settings_section( $full_section_id, $label, $section_callback, static::PAGE_ID ); 243 244 foreach ( $section['fields'] as $field_id => $field ) { 245 $full_field_id = ! empty( $field['full_field_id'] ) ? $field['full_field_id'] : 'elementor_' . $field_id; 246 247 $field['field_args']['id'] = $full_field_id; 248 249 $field_classes = [ $full_field_id ]; 250 251 if ( ! empty( $field['class'] ) ) { 252 $field_classes[] = $field['field_args']['class']; 253 } 254 255 $field['field_args']['class'] = implode( ' ', $field_classes ); 256 257 if ( ! isset( $field['render'] ) ) { 258 $field['render'] = [ $controls_class_name, 'render' ]; 259 } 260 261 add_settings_field( 262 $full_field_id, 263 isset( $field['label'] ) ? $field['label'] : '', 264 $field['render'], 265 static::PAGE_ID, 266 $full_section_id, 267 $field['field_args'] 268 ); 269 270 $setting_args = []; 271 272 if ( ! empty( $field['setting_args'] ) ) { 273 $setting_args = $field['setting_args']; 274 } 275 276 register_setting( static::PAGE_ID, $full_field_id, $setting_args ); 277 } 278 } 279 } 280 } 281 282 /** 283 * Display settings page. 284 * 285 * Output the content for the settings page. 286 * 287 * @since 1.5.0 288 * @access public 289 */ 290 public function display_settings_page() { 291 $this->register_settings_fields(); 292 293 $tabs = $this->get_tabs(); 294 ?> 295 <div class="wrap"> 296 <h1 class="wp-heading-inline"><?php echo esc_html( $this->get_page_title() ); ?></h1> 297 <div id="elementor-settings-tabs-wrapper" class="nav-tab-wrapper"> 298 <?php 299 foreach ( $tabs as $tab_id => $tab ) { 300 if ( empty( $tab['sections'] ) ) { 301 continue; 302 } 303 304 $active_class = ''; 305 306 if ( 'general' === $tab_id ) { 307 $active_class = ' nav-tab-active'; 308 } 309 310 $sanitized_tab_id = esc_attr( $tab_id ); 311 $sanitized_tab_label = esc_html( $tab['label'] ); 312 313 // PHPCS - Escaped the relevant strings above. 314 echo "<a id='elementor-settings-tab-{$sanitized_tab_id}' class='nav-tab{$active_class}' href='#tab-{$sanitized_tab_id}'>{$sanitized_tab_label}</a>"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 315 } 316 ?> 317 </div> 318 <form id="elementor-settings-form" method="post" action="options.php"> 319 <?php 320 settings_fields( static::PAGE_ID ); 321 322 foreach ( $tabs as $tab_id => $tab ) { 323 if ( empty( $tab['sections'] ) ) { 324 continue; 325 } 326 327 $active_class = ''; 328 329 if ( 'general' === $tab_id ) { 330 $active_class = ' elementor-active'; 331 } 332 333 $sanitized_tab_id = esc_attr( $tab_id ); 334 335 // PHPCS - $active_class is a non-dynamic string and $sanitized_tab_id is escaped above. 336 echo "<div id='tab-{$sanitized_tab_id}' class='elementor-settings-form-page{$active_class}'>"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 337 338 foreach ( $tab['sections'] as $section_id => $section ) { 339 $full_section_id = 'elementor_' . $section_id . '_section'; 340 341 if ( ! empty( $section['label'] ) ) { 342 echo '<h2>' . esc_html( $section['label'] ) . '</h2>'; 343 } 344 345 if ( ! empty( $section['callback'] ) ) { 346 $section['callback'](); 347 } 348 349 echo '<table class="form-table">'; 350 351 do_settings_fields( static::PAGE_ID, $full_section_id ); 352 353 echo '</table>'; 354 } 355 356 echo '</div>'; 357 } 358 359 submit_button(); 360 ?> 361 </form> 362 </div><!-- /.wrap --> 363 <?php 364 } 365 366 public function get_usage_fields() { 367 return [ 368 'allow_tracking' => [ 369 'label' => esc_html__( 'Usage Data Sharing', 'elementor' ), 370 'field_args' => [ 371 'type' => 'checkbox', 372 'value' => 'yes', 373 'default' => '', 374 'sub_desc' => esc_html__( 'Become a super contributor by opting in to share non-sensitive plugin data and to receive periodic email updates from us.', 'elementor' ) . sprintf( ' <a href="%1$s" target="_blank">%2$s</a>', 'https://go.elementor.com/usage-data-tracking/', esc_html__( 'Learn more.', 'elementor' ) ), 375 ], 376 'setting_args' => [ __NAMESPACE__ . '\Tracker', 'check_for_settings_optin' ], 377 ], 378 ]; 379 } 380 381 /** 382 * Ensure tabs. 383 * 384 * Make sure the settings page has tabs before inserting any new sections or 385 * fields. 386 * 387 * @since 1.5.0 388 * @access private 389 */ 390 private function ensure_tabs() { 391 if ( null === $this->tabs ) { 392 $this->tabs = $this->create_tabs(); 393 394 $page_id = static::PAGE_ID; 395 396 /** 397 * After create settings. 398 * 399 * Fires after the settings are created in Elementor admin page. 400 * 401 * The dynamic portion of the hook name, `$page_id`, refers to the current page ID. 402 * 403 * @since 1.0.0 404 * 405 * @param Settings_Page $this The settings page. 406 */ 407 do_action( "elementor/admin/after_create_settings/{$page_id}", $this ); 408 } 409 } 410 }