LLMS_Admin_Settings
Admin settings and fields class
Contents
Source Source
File: includes/admin/class.llms.admin.settings.php
class LLMS_Admin_Settings { /** * Settings array * * @var array */ private static $settings = array(); /** * Errors array * * @var array */ private static $errors = array(); /** * Messages array * * @var array */ private static $messages = array(); /** * Instantiates setting page objects, if not already done, and returns them. * * @since 6.0.0 Removed loading of class files that don't instantiate their class in favor of autoloading. * * @return LLMS_Settings_Page[] self::$settings */ public static function get_settings_tabs() { if ( empty( self::$settings ) ) { $settings = array(); $settings[] = include 'settings/class.llms.settings.general.php'; $settings[] = include 'settings/class.llms.settings.courses.php'; $settings[] = include 'settings/class.llms.settings.memberships.php'; $settings[] = include 'settings/class.llms.settings.accounts.php'; $settings[] = include 'settings/class.llms.settings.checkout.php'; $settings[] = include 'settings/class.llms.settings.engagements.php'; $settings[] = include 'settings/class.llms.settings.notifications.php'; $settings[] = include 'settings/class.llms.settings.integrations.php'; /** * Allow 3rd parties to add or remove setting pages. * * @since 1.0.0 * * @param LLMS_Settings_Page[] $settings Setting page objects. */ self::$settings = apply_filters( 'lifterlms_get_settings_pages', $settings ); } return self::$settings; } /** * Save method. Saves all fields on current tab * * @return void */ public static function save() { global $current_tab; if ( isset( $_POST['_wpnonce'] ) && ! llms_verify_nonce( '_wpnonce', 'lifterlms-settings' ) ) { die( __( 'Whoa! something went wrong there!. Please refresh the page and retry.', 'lifterlms' ) ); } do_action( 'lifterlms_settings_save_' . $current_tab ); do_action( 'lifterlms_update_options_' . $current_tab ); do_action( 'lifterlms_update_options' ); self::set_message( __( 'Your settings have been saved.', 'lifterlms' ) ); do_action( 'lifterlms_settings_saved' ); do_action( 'lifterlms_settings_saved_' . $current_tab ); } /** * set message to messages array * * @param string $message * @return void */ public static function set_message( $message ) { self::$messages[] = $message; } /** * set message to messages array * * @param string $message * @return void */ public static function set_error( $message ) { self::$errors[] = $message; } /** * display messages in settings * * @return void */ public static function display_messages_html() { if ( count( self::$errors ) > 0 ) { foreach ( self::$errors as $error ) { echo '<div class="error"><p><strong>' . $error . '</strong></p></div>'; } } elseif ( count( self::$messages ) > 0 ) { foreach ( self::$messages as $message ) { echo '<div class="updated"><p><strong>' . $message . '</strong></p></div>'; } } } /** * Settings Page output tabs * * @since 1.0.0 * @since 3.29.0 Unknown. * @since 3.35.0 Sanitize `$_GET` data. * @since 3.35.1 Fix issue causing data to be saved on every page load. * @since 5.9.0 Stop using deprecated `FILTER_SANITIZE_STRING`. * * @return void */ public static function output() { global $current_tab; do_action( 'lifterlms_settings_start' ); self::get_settings_tabs(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce is checked in self::save(). $current_tab = empty( $_GET['tab'] ) ? 'general' : llms_filter_input_sanitize_string( INPUT_GET, 'tab' ); // phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce is checked in self::save(). if ( ! empty( $_POST ) ) { self::save(); } // phpcs:enable WordPress.Security.NonceVerification.Missing. $err = llms_filter_input_sanitize_string( INPUT_GET, 'llms_error' ); if ( $err ) { self::set_error( $err ); } $msg = llms_filter_input_sanitize_string( INPUT_GET, 'llms_message' ); if ( $msg ) { self::set_message( $msg ); } self::display_messages_html(); $tabs = apply_filters( 'lifterlms_settings_tabs_array', array() ); include 'views/settings.php'; } /** * Output fields for settings tabs. Dynamically generates fields. * * Needs to be refactored! Sets up all of the fields..gross... * * @return void */ public static function output_fields( $settings ) { foreach ( $settings as $field ) { // Skip item if no field type is set. if ( ! isset( $field['type'] ) ) { continue; } // Output the field. self::output_field( $field ); } } /** * Output fields * * @since Unknown. * @since 3.29.0 Unknown. * @since 3.34.4 Add "keyval" field for displaying custom html next to a setting key. * @since 3.37.9 Add option for fields to show an asterisk for required fields. * @since 5.0.2 Pass any option value sanitized as a "slug" through `urldecode()` prior to displaying it. * @since 7.0.0 Add `$after_html` to all field types. * * @param array $field { * Array of field settings. * * @type string $id The setting ID. Used as the from element's `name` and `id` attributes and * automatically correspond to an option key using the WP options API. * @type string $type The field type. Accepts: 'title', 'table', 'subtitle', 'desc', 'custom-html', * 'custom-html-no-wrap', 'sectionstart', 'sectionend', 'button', 'hidden', 'keyval', * 'text', 'email', 'number', 'password', 'textarea', 'wpeditor', 'select', 'multiselect', * 'radio', 'checkbox', 'image', 'single_select_page', 'single_select_membership'. * @type string $title The title / name of the option as displayed to the user. * @type string $name For "button" fields only: used as HTML `name` attribute. If not supplied the default * value "save" will be used. For other field types used as a fallback for `$title` if * no value is supplied. * @type string $class A space-separated list of CSS class names to apply the setting form element (the * `<input>`, `<select>` etc...). * @type string $css An inline CSS style string. * @type string $default The default value of the setting. * @type string $desc The setting's description. * @type bool $desc_tooltip If `true`, displays `$desc` in a hoverable tooltip. * @type string $value The value of the setting. If supplied this will override the automatic setting retrieval * using `get_option( $id, $default )`. * @type array $custom_attributes An associative array of custom HTML attributes to be added to the form element (the * `<input>`, `<select>` etc...). * @type bool $disabled If `true` adds the `llms-disabled-field` class to the settings field wrapper. * @type bool $required If `true`, text, email, number, and password fields will require user input. * @type string $secure_option The name of settings secure option equivalent. If specified, the fields value will be * automatically removed from the database and the value will be masked when displayed on * on screen. See {@see llms_get_secure_option()} for more information. * @type string $sanitize Automatically apply the specified sanitization to the value before storing and outputting * the stored value. Supported filters: * + "slug": Uses `sanitize_title()` on the value when storing and `urldecode()` when displaying. * @type string $after_html Additional HTML to add after the field's form element. * @type array $editor_settings Used with "wpeditor" field type only. An array of options to pass to `wp_editor()` as the `$settings` argument. * @type array $options For "select", "multiselect", and "radio" fields, an array of key/value pairs where the * key is the setting value stored in database and the value is the setting label displayed * on screen. * } * @return void */ public static function output_field( $field ) { // Set missing values with defaults. $field = self::set_field_defaults( $field ); // Setup custom attributes. $custom_attributes = self::format_field_custom_attributes( $field['custom_attributes'] ?? array() ); // Setup field description and tooltip. extract( self::set_field_descriptions( $field ) ); $description .= ' ' . $field['after_html']; // Get the field value. $option_value = isset( $field['value'] ) ? $field['value'] : self::get_option( $field['id'], $field['default'] ); // Setup the disabled CSS class. $disabled_class = ( isset( $field['disabled'] ) && true === $field['disabled'] ) ? 'llms-disabled-field' : ''; // Switch based on type. switch ( $field['type'] ) { // Section Titles. case 'title': if ( ! empty( $field['title'] ) ) { echo '<p class="llms-label">' . esc_html( $field['title'] ) . '</p>'; } if ( ! empty( $field['desc'] ) ) { echo '<p class="llms-description">' . wpautop( wptexturize( wp_kses_post( $field['desc'] ) ) ) . '</p>'; } echo '<table class="form-table">' . "\n\n"; if ( ! empty( $field['id'] ) ) { do_action( 'lifterlms_settings_' . sanitize_title( $field['id'] ) ); } break; case 'table': echo '<tr valign="top" class="' . $disabled_class . '"><td>'; $field['table']->get_results(); echo $field['table']->get_table_html(); echo '</td></tr>'; break; case 'subtitle': if ( ! empty( $field['title'] ) ) { echo '<tr valign="top" class="' . $disabled_class . '"><td colspan="2"> <h3 class="llms-subtitle">' . $field['title'] . '</h3>'; if ( ! empty( $field['desc'] ) ) { echo '<p>' . $field['desc'] . '</p>'; } echo '</tr></td>'; } break; case 'desc': if ( ! empty( $field['desc'] ) ) { echo '<th colspan="2" style="font-weight: normal;">' . wpautop( wptexturize( wp_kses_post( $field['desc'] ) ) ) . '</th>'; } break; case 'custom-html': if ( ! empty( $field['value'] ) ) { echo '<tr valign="top" class="' . $disabled_class . '"><td colspan="2">' . $field['value'] . '</tr></td>'; } break; case 'custom-html-no-wrap': if ( ! empty( $field['value'] ) ) { echo $field['value']; } break; case 'sectionstart': if ( ! empty( $field['id'] ) ) { do_action( 'lifterlms_settings_' . sanitize_title( $field['id'] ) . '_before' ); echo '<div class="llms-setting-group ' . $field['class'] . '">'; do_action( 'lifterlms_settings_' . sanitize_title( $field['id'] ) . '_start' ); } break; case 'sectionend': if ( ! empty( $field['id'] ) ) { do_action( 'lifterlms_settings_' . sanitize_title( $field['id'] ) . '_end' ); } echo '</table>'; echo '</div>'; if ( ! empty( $field['id'] ) ) { do_action( 'lifterlms_settings_' . sanitize_title( $field['id'] ) . '_after' ); } break; case 'button': $name = isset( $field['name'] ) ? $field['name'] : 'save'; echo '<tr valign="top" class="' . $disabled_class . '"><th> <label for="' . esc_attr( $field['id'] ) . '">' . esc_html( $field['title'] ) . '</label> ' . $tooltip . ' </th>'; echo '<td class="forminp forminp-' . sanitize_title( $field['type'] ) . '">'; echo '<div id="llms-form-wrapper">'; echo $description . '<br><br>'; echo '<input name="' . $name . '" class="llms-button-primary" type="submit" value="' . esc_attr( $field['value'] ) . '" />'; echo '</div>'; echo '</td></tr>'; // phpcs:ignore -- commented out code // get_submit_button( 'Filter Results', 'primary', 'llms_search', true, array( 'id' => 'llms_analytics_search' ) ); break; case 'hidden': echo '<th></th>'; echo '<td><input type="hidden" name="' . esc_attr( $field['id'] ) . '" id="' . esc_attr( $field['id'] ) . '" value="' . esc_attr( $field['value'] ) . '">'; break; case 'keyval': ?><tr valign="top"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <div id="<?php echo esc_attr( $field['id'] ); ?>"><?php echo $field['value']; ?></div> </td> </tr> <?php break; case 'text': case 'email': case 'number': case 'password': $type = $field['type']; $class = ''; $required = ! empty( $field['required'] ); $secure_val = isset( $field['secure_option'] ) ? llms_get_secure_option( $field['secure_option'], false ) : false; $option_value = ( false !== $secure_val ) ? str_repeat( '*', strlen( $secure_val ) ) : $option_value; // Ensure slugs with non-latin characters are not displayed as urlencoded strings. if ( ! empty( $field['sanitize'] ) && 'slug' === $field['sanitize'] ) { $option_value = urldecode( $option_value ); } ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"> <?php echo esc_html( $field['title'] ); ?> <?php echo $required ? '<span class="llms-required">*</span>' : ''; ?> </label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <input name="<?php echo esc_attr( $field['id'] ); ?>" id="<?php echo esc_attr( $field['id'] ); ?>" type="<?php echo esc_attr( $type ); ?>" style="<?php echo esc_attr( $field['css'] ); ?>" value="<?php echo esc_attr( $option_value ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" <?php echo $secure_val ? 'disabled="disabled"' : ''; ?> <?php echo implode( ' ', $custom_attributes ); ?> <?php echo $required ? 'required="required"' : ''; ?> /> <?php echo $description; ?> </td> </tr> <?php break; // Textarea. case 'textarea': ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <textarea name="<?php echo esc_attr( $field['id'] ); ?>" id="<?php echo esc_attr( $field['id'] ); ?>" style="<?php echo esc_attr( $field['css'] ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" <?php echo implode( ' ', $custom_attributes ); ?> ><?php echo esc_textarea( $option_value ); ?></textarea> <?php echo $description; ?> </td> </tr> <?php break; case 'wpeditor': $editor_settings = isset( $field['editor_settings'] ) ? $field['editor_settings'] : array(); ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <?php wp_editor( $option_value, $field['id'], $editor_settings ); ?> <?php echo $description; ?> </td> </tr> <?php break; // Select boxes. case 'select': case 'multiselect': $field_name = esc_attr( $field['id'] ); if ( 'multiselect' === $field['type'] ) { $field_name .= '[]'; } ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <select name="<?php echo $field_name; ?>" id="<?php echo esc_attr( $field['id'] ); ?>" style="<?php echo esc_attr( $field['css'] ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" <?php echo implode( ' ', $custom_attributes ); ?> <?php if ( 'multiselect' === $field['type'] ) { echo 'multiple="multiple"'; } ?> > <?php foreach ( $field['options'] as $key => $val ) { // Convert an array from llms_make_select2_post_array(). if ( is_array( $val ) ) { $key = $val['key']; $val = $val['title']; } ?> <option value="<?php echo esc_attr( $key ); ?>" <?php if ( is_array( $option_value ) ) { selected( in_array( $key, $option_value ), true ); } else { selected( $option_value, $key ); } ?> ><?php echo $val; ?></option> <?php } ?> </select> <?php echo $description; ?> </td> </tr> <?php break; // Radio inputs. case 'radio': ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <fieldset> <?php echo $description; ?> <ul> <?php foreach ( $field['options'] as $key => $val ) { ?> <li> <label><input name="<?php echo esc_attr( $field['id'] ); ?>" value="<?php echo $key; ?>" type="radio" style="<?php echo esc_attr( $field['css'] ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" <?php echo implode( ' ', $custom_attributes ); ?> <?php checked( $key, $option_value ); ?> /> <?php echo $val; ?></label> </li> <?php } ?> </ul> </fieldset> </td> </tr> <?php break; // Checkbox input. case 'checkbox': $visbility_class = array(); if ( ! isset( $field['hide_if_checked'] ) ) { $field['hide_if_checked'] = false; } if ( ! isset( $field['show_if_checked'] ) ) { $field['show_if_checked'] = false; } if ( 'yes' === $field['hide_if_checked'] || 'yes' === $field['show_if_checked'] ) { $visbility_class[] = 'hidden_option'; } if ( 'option' === $field['hide_if_checked'] ) { $visbility_class[] = 'hide_options_if_checked'; } if ( 'option' === $field['show_if_checked'] ) { $visbility_class[] = 'show_options_if_checked'; } if ( ! isset( $field['checkboxgroup'] ) || 'start' === $field['checkboxgroup'] ) { ?> <tr valign="top" class="<?php echo esc_attr( implode( ' ', $visbility_class ) ); ?> <?php echo $disabled_class; ?>"> <th><?php echo esc_html( $field['title'] ); ?></th> <td class="forminp forminp-checkbox"> <fieldset> <?php } else { ?> <fieldset class="<?php echo esc_attr( implode( ' ', $visbility_class ) ); ?>"> <?php } if ( ! empty( $field['title'] ) ) { ?> <legend class="screen-reader-text"><span><?php echo esc_html( $field['title'] ); ?></span></legend> <?php } ?> <label for="<?php echo $field['id']; ?>"> <input name="<?php echo esc_attr( $field['id'] ); ?>" id="<?php echo esc_attr( $field['id'] ); ?>" type="checkbox" value="1" <?php checked( $option_value, 'yes' ); ?> <?php echo implode( ' ', $custom_attributes ); ?> /> <?php echo $description; ?> </label> <?php echo $tooltip; ?> <?php if ( ! isset( $field['checkboxgroup'] ) || 'end' === $field['checkboxgroup'] ) { ?> </fieldset> </td> </tr> <?php } else { ?> </fieldset> <?php } break; case 'image': $type = $field['type']; $class = ''; if ( $option_value ) { // Media lib object ID. if ( is_numeric( $option_value ) ) { $size = isset( $field['image_size'] ) ? $field['image_size'] : 'medium'; $attachment = wp_get_attachment_image_src( $option_value, $size ); $src = $attachment[0]; } else { // Raw img src. $src = $option_value; } } else { $src = ''; } ?> <tr valign="top" class="<?php echo $disabled_class; ?>"> <th> <label for="<?php echo esc_attr( $field['id'] ); ?>"><?php echo esc_html( $field['title'] ); ?></label> <?php echo $tooltip; ?> </th> <td class="forminp forminp-<?php echo sanitize_title( $field['type'] ); ?>"> <img class="llms-image-field-preview" src="<?php echo $src; ?>"> <button class="llms-button-secondary llms-image-field-upload" data-id="<?php echo esc_attr( $field['id'] ); ?>" type="button"> <span class="dashicons dashicons-admin-media"></span> <?php _e( 'Upload', 'lifterlms' ); ?> </button> <button class="llms-button-danger llms-image-field-remove<?php echo ( ! $src ) ? ' hidden' : ''; ?>" data-id="<?php echo esc_attr( $field['id'] ); ?>" type="button"> <span class="dashicons dashicons-no"></span> </button> <input name="<?php echo esc_attr( $field['id'] ); ?>" id="<?php echo esc_attr( $field['id'] ); ?>" type="hidden" style="<?php echo esc_attr( $field['css'] ); ?>" value="<?php echo esc_attr( $option_value ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" <?php echo implode( ' ', $custom_attributes ); ?> /> <?php echo $description; ?> </td> </tr> <?php break; // Single page selects. case 'single_select_page': $args = array( 'name' => $field['id'], 'id' => $field['id'], 'sort_column' => 'menu_order', 'sort_order' => 'ASC', 'show_option_none' => ' ', 'class' => $field['class'], 'echo' => false, 'selected' => absint( self::get_option( $field['id'] ) ), ); if ( isset( $field['args'] ) ) { $args = wp_parse_args( $field['args'], $args ); } ?> <tr valign="top" class="single_select_page"> <th><?php echo esc_html( $field['title'] ); ?> <?php echo $tooltip; ?></th> <td class="forminp"> <?php echo str_replace( ' id=', " data-placeholder='" . __( 'Select a page…', 'lifterlms' ) . "' style='" . $field['css'] . "' class='" . $field['class'] . "' id=", wp_dropdown_pages( $args ) ); ?> <?php echo $description; ?> </td> </tr> <?php break; // Single page selects. case 'single_select_membership': $args = array( 'posts_per_page' => -1, 'post_type' => 'llms_membership', 'nopaging' => true, 'post_status' => 'publish', 'class' => $field['class'], 'selected' => absint( self::get_option( $field['id'] ) ), ); $posts = get_posts( $args ); if ( isset( $field['args'] ) ) { $args = wp_parse_args( $field['args'], $args ); } ?> <tr valign="top" class="single_select_membership"> <th><?php echo esc_html( $field['title'] ); ?> <?php echo $tooltip; ?></th> <td class="forminp"> <select class="<?php echo $args['class']; ?>" style="<?php echo $field['css']; ?>" name="lifterlms_membership_required" id="lifterlms_membership_required"> <option value=""> <?php _e( 'None', 'lifterlms' ); ?></option> <?php foreach ( $posts as $post ) : setup_postdata( $post ); if ( $args['selected'] === $post->ID ) { $selected = 'selected'; } else { $selected = ''; } ?> <option value="<?php echo $post->ID; ?>" <?php echo $selected; ?> ><?php echo $post->post_title; ?></option> <?php endforeach; ?> </select> </td> </tr> <?php break; // Default: run an action. default: do_action( 'lifterlms_admin_field_' . $field['type'], $field, $option_value, $description, $tooltip, $custom_attributes ); break; } } /** * Add and set default values for a field when looping * * @since 1.4.5 * @since 7.0.0 Use `wp_parse_args()` to simplify method logic & add `after_html` default. * * @param array $field Associative array of field data, {@see LLMS_Admin_Settings::output_field()} for a full description. * @return array */ public static function set_field_defaults( $field = array() ) { $field = wp_parse_args( $field, array( 'id' => '', 'title' => $field['name'] ?? '', 'class' => '', 'css' => '', 'default' => '', 'desc' => '', 'desc_tooltip' => '', 'after_html' => '', ) ); return $field; } /** * Setup a field's tooltip and description based on supplied values * * @since 1.4.5 * @since 3.24.0 Unknown. * @since 4.2.0 Use a dashicon in place of image for tooltip icon. * * @param array $field Associative array of field data. * @return array { * Associative array containing field description and tooltip HTML. * * @type string $description Description element HTML. * @type string $tooltip Tooltip element HTML. * } */ public static function set_field_descriptions( $field = array() ) { $description = ''; $tooltip = ''; if ( true === $field['desc_tooltip'] ) { $description = ''; $tooltip = $field['desc']; } elseif ( ! empty( $field['desc_tooltip'] ) ) { $description = $field['desc']; $tooltip = $field['desc_tooltip']; } elseif ( ! empty( $field['desc'] ) ) { $description = $field['desc']; $tooltip = ''; } if ( $description && in_array( $field['type'], array( 'radio' ), true ) ) { $description = '<p style="margin-top:0">' . wp_kses_post( $description ) . '</p>'; } elseif ( $description && in_array( $field['type'], array( 'checkbox' ), true ) ) { $description = wp_kses_post( $description ); } elseif ( $description ) { $description = '<p class="description">' . wp_kses_post( $description ) . '</p>'; } if ( $tooltip && in_array( $field['type'], array( 'checkbox' ), true ) ) { $tooltip = '<p class="description">' . $tooltip . '</p>'; } elseif ( $tooltip ) { $position = isset( $field['tooltip_position'] ) ? $field['tooltip_position'] : 'top-right'; $tooltip = '<span class="llms-help-tooltip tip--' . esc_attr( $position ) . '" data-tip="' . esc_attr( $tooltip ) . '"><span class="dashicons dashicons-editor-help"></span></span>'; } return compact( 'description', 'tooltip' ); } /** * Formats an associative array of custom field attributes as an array of HTML strings * * @param array $attributes associative array of attributes * @return array * * @since 1.4.5 */ public static function format_field_custom_attributes( $attributes = array() ) { // Custom attribute handling. $custom_attributes = array(); foreach ( $attributes as $attribute => $attribute_value ) { $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"'; } return $custom_attributes; } /** * Get a setting from the settings API. * * @since Unknown * @since 3.7.5 Unknown * * @param string $option_name Option name. * @param mixed $default Optional default value. * @return string */ public static function get_option( $option_name, $default = '' ) { // Array value. if ( strstr( $option_name, '[' ) ) { parse_str( $option_name, $option_array ); // Option name is first key. $option_name = current( array_keys( $option_array ) ); // Get value. $option_values = get_option( $option_name, '' ); $key = key( $option_array[ $option_name ] ); if ( isset( $option_values[ $key ] ) ) { $option_value = $option_values[ $key ]; } else { $option_value = null; } } else { $option_value = get_option( $option_name, null ); } if ( is_array( $option_value ) ) { $option_value = array_map( 'stripslashes', $option_value ); } elseif ( ! is_null( $option_value ) ) { $option_value = stripslashes( $option_value ); } return null === $option_value ? $default : $option_value; } /** * Save admin fields. * * Loops through a LifterLMS settings field options array and saves the values via `update_option()`. * * @since 1.0.0 * @since 3.29.0 Unknown. * @since 3.35.0 Sanitize `$_POST` data. * @since 3.35.2 Don't strip tags on editor and textarea fields that allow HTML. * @since 5.9.0 Stop using deprecated `FILTER_SANITIZE_STRING`. * @since 7.0.0 Add handling for array fields for standard input types. * Account for the `maxlength` input text and textarea attribute. * * @param array $settings Opens array to output * @return boolean */ public static function save_fields( $settings ) { // phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce is checked in self::save(). if ( empty( $_POST ) ) { return false; } // Options to update will be stored here. $update_options = array(); // Loop options and get values to save. foreach ( $settings as $field ) { if ( ! isset( $field['id'] ) ) { continue; } $type = isset( $field['type'] ) ? sanitize_title( $field['type'] ) : ''; // Remove secure options from the database. if ( isset( $field['secure_option'] ) && llms_get_secure_option( $field['secure_option'] ) ) { delete_option( $field['id'] ); continue; } // Get the option name. $option_value = null; // Determines if the option value is an array. $is_array_option = false !== strpos( $field['id'], '[' ); switch ( $type ) { case 'checkbox': if ( $is_array_option ) { $option_value = self::get_array_field_posted_value( $field['id'] ) ? 'yes' : 'no'; } elseif ( isset( $_POST[ $field['id'] ] ) ) { $option_value = 'yes'; } else { $option_value = 'no'; } break; case 'textarea': case 'wpeditor': if ( isset( $_POST[ $field['id'] ] ) ) { $option_value = wp_kses_post( trim( llms_filter_input( INPUT_POST, $field['id'], FILTER_DEFAULT ) ) ); } else { $option_value = ''; } break; case 'password': case 'text': case 'email': case 'number': case 'select': case 'single_select_page': case 'single_select_membership': case 'radio': case 'hidden': case 'image': if ( $is_array_option ) { $option_value = self::get_array_field_posted_value( $field['id'] ); } elseif ( isset( $_POST[ $field['id'] ] ) ) { $option_value = llms_filter_input_sanitize_string( INPUT_POST, $field['id'] ); } else { $option_value = ''; } if ( isset( $field['sanitize'] ) && 'slug' === $field['sanitize'] ) { $option_value = sanitize_title( $option_value ); } break; case 'multiselect': if ( isset( $_POST[ $field['id'] ] ) ) { $option_value = llms_filter_input_sanitize_string( INPUT_POST, $field['id'], array( FILTER_REQUIRE_ARRAY ) ); } else { $option_value = ''; } break; default: /** * Action run for external field types. * * @since Unknown * @deprecated 7.0.0 Use `llms_update_option_{$type}` filter hook instead. * * @param type $arg Description. */ do_action_deprecated( "lifterlms_update_option_{$type}", array( $field ), '7.0.0' ); } // Special treatment for the 'maxlength' attribute. if ( in_array( $type, array( 'text', 'textarea' ), true ) && isset( $field['custom_attributes']['maxlength'] ) ) { $option_value = llms_trim_string( $option_value, (int) $field['custom_attributes']['maxlength'], '' ); } /** * Filters the value of a settings field after it has been parsed and sanitized * and before it is saved to the database. * * The dynamic portion of this hook, `{$type}` refers to the setting field type: * email, text, checkbox, etc... * * @since 7.0.0 * * @param string|null $option_value The sanitized option value or `null`. * @param array $field The settings field array. */ $option_value = apply_filters( "llms_update_option_{$type}", $option_value, $field ); if ( ! is_null( $option_value ) ) { if ( $is_array_option ) { parse_str( $field['id'], $option_array ); // Option name is first key. $option_name = current( array_keys( $option_array ) ); // Get old option value. if ( ! isset( $update_options[ $option_name ] ) ) { $update_options[ $option_name ] = get_option( $option_name, array() ); } if ( ! is_array( $update_options[ $option_name ] ) ) { $update_options[ $option_name ] = array(); } // Set keys and value. $key = key( $option_array[ $option_name ] ); $update_options[ $option_name ][ $key ] = $option_value; } else { $update_options[ $field['id'] ] = $option_value; } } /** * Action run prior to the update of a LifterLMS setting field option. * * An update isn't guaranteed after this action if the method's logic can't * find a valid posted valued to persist to the database. * * @since Unknown * * @param array $field The admin setting field array to be updated. */ do_action( 'lifterlms_update_option', $field ); } // Now save the options. foreach ( $update_options as $name => $value ) { update_option( $name, $value ); } // phpcs:enable WordPress.Security.NonceVerification.Missing return true; } /** * Retrieves the posted value for an array type setting field. * * @since 7.0.0 * * @param string $id The field ID, eg: "my_setting[field_one]". * @return string Returns the (sanitized) posted value or an empty string if it wasn't posted. */ private static function get_array_field_posted_value( $id ) { parse_str( $id, $parsed_id ); $opt_id = key( $parsed_id ); $opt_key = key( $parsed_id[ $opt_id ] ); $posted = llms_filter_input_sanitize_string( INPUT_POST, $opt_id, array( FILTER_REQUIRE_ARRAY ) ); return $posted[ $opt_key ] ?? ''; } }
Expand full source code Collapse full source code View on GitHub
Methods Methods
- display_messages_html — display messages in settings
- format_field_custom_attributes — Formats an associative array of custom field attributes as an array of HTML strings
- get_array_field_posted_value — Retrieves the posted value for an array type setting field.
- get_option — Get a setting from the settings API.
- get_settings_tabs — Instantiates setting page objects, if not already done, and returns them.
- output — Settings Page output tabs
- output_field — Output fields
- output_fields — Output fields for settings tabs. Dynamically generates fields.
- save — Save method. Saves all fields on current tab
- save_fields — Save admin fields.
- set_error — set message to messages array
- set_field_defaults — Add and set default values for a field when looping
- set_field_descriptions — Setup a field's tooltip and description based on supplied values
- set_message — set message to messages array
Changelog Changelog
Version | Description |
---|---|
4.2.0 | Use dashicons for tooltip icon display. |
3.37.9 | Add option for fields to show an asterisk for required fields. |
3.35.2 | Don't strip tags on editor and textarea fields that allow HTML. |
3.35.1 | Fix saving issue. |
3.35.0 | Sanitize input data. |
3.34.4 | Add "keyval" field for displaying custom html next to a setting key. |
3.29.0 | Unknown. |
1.0.0 | Introduced. |