if ( ! isset( $wp_meta_boxes ) ) {
$wp_meta_boxes = array();
if ( ! isset( $wp_meta_boxes[ $page ] ) ) {
$wp_meta_boxes[ $page ] = array();
if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
$wp_meta_boxes[ $page ][ $context ] = array();
foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
$wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = false;
* Meta Box Accordion Template Function.
* Largely made up of abstracted code from do_meta_boxes(), this
* function serves to build meta boxes as list items for display as
* a collapsible accordion.
* @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
* @param string|object $screen The screen identifier.
* @param string $context The screen context for which to display accordion sections.
* @param mixed $data_object Gets passed to the section callback function as the first parameter.
* @return int Number of meta boxes as accordion sections.
function do_accordion_sections( $screen, $context, $data_object ) {
wp_enqueue_script( 'accordion' );
if ( empty( $screen ) ) {
$screen = get_current_screen();
} elseif ( is_string( $screen ) ) {
$screen = convert_to_screen( $screen );
$hidden = get_hidden_meta_boxes( $screen );
<div id="side-sortables" class="accordion-container">
<ul class="outer-border">
if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
if ( false === $box || ! $box['title'] ) {
$hidden_class = in_array( $box['id'], $hidden, true ) ? 'hide-if-js' : '';
$aria_expanded = 'false';
if ( ! $first_open && empty( $hidden_class ) ) {
<li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
<h3 class="accordion-section-title hndle">
<button type="button" class="accordion-trigger" aria-expanded="<?php echo $aria_expanded; ?>" aria-controls="<?php echo esc_attr( $box['id'] ); ?>-content">
<span class="accordion-title">
<?php echo esc_html( $box['title'] ); ?>
<span class="dashicons dashicons-arrow-down" aria-hidden="true"></span>
<div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>-content">
<?php call_user_func( $box['callback'], $data_object, $box ); ?>
</div><!-- .accordion-section-content -->
</li><!-- .accordion-section -->
</ul><!-- .outer-border -->
</div><!-- .accordion-container -->
* Adds a new section to a settings page.
* Part of the Settings API. Use this to define new settings sections for an admin page.
* Show settings sections in your admin page callback function with do_settings_sections().
* Add settings fields to your section with add_settings_field().
* The $callback argument should be the name of a function that echoes out any
* content you want to show at the top of the settings section before the actual
* fields. It can output nothing if you want.
* @since 6.1.0 Added an `$args` parameter for the section's HTML wrapper and class name.
* @global array $wp_settings_sections Storage array of all settings sections added to admin pages.
* @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
* @param string $title Formatted title of the section. Shown as the heading for the section.
* @param callable $callback Function that echos out any content at the top of the section (between heading and fields).
* @param string $page The slug-name of the settings page on which to show the section. Built-in pages include
* 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using
* Arguments used to create the settings section.
* @type string $before_section HTML content to prepend to the section's HTML output.
* Receives the section's class name as `%s`. Default empty.
* @type string $after_section HTML content to append to the section's HTML output. Default empty.
* @type string $section_class The class name to use for the section. Default empty.
function add_settings_section( $id, $title, $callback, $page, $args = array() ) {
global $wp_settings_sections;
$section = wp_parse_args( $args, $defaults );
if ( 'misc' === $page ) {
/* translators: %s: misc */
__( 'The "%s" options group has been removed. Use another settings group.' ),
if ( 'privacy' === $page ) {
/* translators: %s: privacy */
__( 'The "%s" options group has been removed. Use another settings group.' ),
$wp_settings_sections[ $page ][ $id ] = $section;
* Adds a new field to a section of a settings page.
* Part of the Settings API. Use this to define a settings field that will show
* as part of a settings section inside a settings page. The fields are shown using
* do_settings_fields() in do_settings_sections().
* The $callback argument should be the name of a function that echoes out the
* HTML input tags for this setting field. Use get_option() to retrieve existing
* @since 4.2.0 The `$class` argument was added.
* @global array $wp_settings_fields Storage array of settings fields and info about their pages/sections.
* @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
* @param string $title Formatted title of the field. Shown as the label for the field
* @param callable $callback Function that fills the field with the desired form inputs. The
* function should echo its output.
* @param string $page The slug-name of the settings page on which to show the section
* (general, reading, writing, ...).
* @param string $section Optional. The slug-name of the section of the settings page
* in which to show the box. Default 'default'.
* Optional. Extra arguments that get passed to the callback function.
* @type string $label_for When supplied, the setting title will be wrapped
* in a `<label>` element, its `for` attribute populated
* @type string $class CSS Class to be added to the `<tr>` element when the
function add_settings_field( $id, $title, $callback, $page, $section = 'default', $args = array() ) {
global $wp_settings_fields;
if ( 'misc' === $page ) {
/* translators: %s: misc */
__( 'The "%s" options group has been removed. Use another settings group.' ),
if ( 'privacy' === $page ) {
/* translators: %s: privacy */
__( 'The "%s" options group has been removed. Use another settings group.' ),
$wp_settings_fields[ $page ][ $section ][ $id ] = array(
* Prints out all settings sections added to a particular settings page.
* Part of the Settings API. Use this in a settings page callback function
* to output all the sections and fields that were added to that $page with
* add_settings_section() and add_settings_field()
* @global array $wp_settings_sections Storage array of all settings sections added to admin pages.
* @global array $wp_settings_fields Storage array of settings fields and info about their pages/sections.
* @param string $page The slug name of the page whose settings sections you want to output.
function do_settings_sections( $page ) {
global $wp_settings_sections, $wp_settings_fields;
if ( ! isset( $wp_settings_sections[ $page ] ) ) {
foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
if ( '' !== $section['before_section'] ) {
if ( '' !== $section['section_class'] ) {
echo wp_kses_post( sprintf( $section['before_section'], esc_attr( $section['section_class'] ) ) );
echo wp_kses_post( $section['before_section'] );
if ( $section['title'] ) {
echo "<h2>{$section['title']}</h2>\n";
if ( $section['callback'] ) {
call_user_func( $section['callback'], $section );
if ( isset( $wp_settings_fields[ $page ][ $section['id'] ] ) ) {
echo '<table class="form-table" role="presentation">';
do_settings_fields( $page, $section['id'] );
if ( '' !== $section['after_section'] ) {
echo wp_kses_post( $section['after_section'] );
* Prints out the settings fields for a particular settings section.
* Part of the Settings API. Use this in a settings page to output
* a specific section. Should normally be called by do_settings_sections()
* @global array $wp_settings_fields Storage array of settings fields and their pages/sections.
* @param string $page Slug title of the admin page whose settings fields you want to show.
* @param string $section Slug title of the settings section whose fields you want to show.
function do_settings_fields( $page, $section ) {
global $wp_settings_fields;
if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) {
foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) {
if ( ! empty( $field['args']['class'] ) ) {
$class = ' class="' . esc_attr( $field['args']['class'] ) . '"';
if ( ! empty( $field['args']['label_for'] ) ) {
echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
echo '<th scope="row">' . $field['title'] . '</th>';
call_user_func( $field['callback'], $field['args'] );
* Registers a settings error to be displayed to the user.
* Part of the Settings API. Use this to show messages to users about settings validation
* problems, missing settings or anything else.
* Settings errors should be added inside the $sanitize_callback function defined in
* register_setting() for a given setting to give feedback about the submission.
* By default messages will show immediately after the submission that generated the error.
* Additional calls to settings_errors() can be used to show errors even when the settings
* page is first accessed.
* @since 5.3.0 Added `warning` and `info` as possible values for `$type`.
* @global array[] $wp_settings_errors Storage array of errors registered during this pageload
* @param string $setting Slug title of the setting to which this error applies.
* @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
* @param string $message The formatted message text to display to the user (will be shown inside styled
* `<div>` and `<p>` tags).
* @param string $type Optional. Message type, controls HTML class. Possible values include 'error',
* 'success', 'warning', 'info'. Default 'error'.
function add_settings_error( $setting, $code, $message, $type = 'error' ) {
global $wp_settings_errors;
$wp_settings_errors[] = array(
* Fetches settings errors registered by add_settings_error().
* Checks the $wp_settings_errors array for any errors declared during the current
* pageload and returns them.
* If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
* to the 'settings_errors' transient then those errors will be returned instead. This
* is used to pass errors back across pageloads.
* Use the $sanitize argument to manually re-sanitize the option before returning errors.
* This is useful if you have errors or notices you want to show even when the user
* hasn't submitted data (i.e. when they first load an options page, or in the {@see 'admin_notices'}
* @global array[] $wp_settings_errors Storage array of errors registered during this pageload
* @param string $setting Optional. Slug title of a specific setting whose errors you want.
* @param bool $sanitize Optional. Whether to re-sanitize the setting value before returning errors.
* Array of settings error arrays.
* Associative array of setting error data.
* @type string $setting Slug title of the setting to which this error applies.
* @type string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
* @type string $message The formatted message text to display to the user (will be shown inside styled
* `<div>` and `<p>` tags).
* @type string $type Optional. Message type, controls HTML class. Possible values include 'error',
* 'success', 'warning', 'info'. Default 'error'.
function get_settings_errors( $setting = '', $sanitize = false ) {
global $wp_settings_errors;
* If $sanitize is true, manually re-run the sanitization for this option
* This allows the $sanitize_callback from register_setting() to run, adding
* any settings errors you want to show by default.
sanitize_option( $setting, get_option( $setting ) );
// If settings were passed back from options.php then use them.
if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
$wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
delete_transient( 'settings_errors' );
// Check global in case errors have been added on this pageload.
if ( empty( $wp_settings_errors ) ) {
// Filter the results to those of a specific setting if one was set.
$setting_errors = array();
foreach ( (array) $wp_settings_errors as $key => $details ) {
if ( $setting === $details['setting'] ) {
$setting_errors[] = $wp_settings_errors[ $key ];
return $wp_settings_errors;
* Displays settings errors registered by add_settings_error().
* Part of the Settings API. Outputs a div for each error retrieved by
* This is called automatically after a settings page based on the
* Settings API is submitted. Errors should be added during the validation
* callback function for a setting defined in register_setting().
* The $sanitize option is passed into get_settings_errors() and will
* re-run the setting sanitization
* The $hide_on_update option will cause errors to only show when the settings
* page is first loaded. if the user has already saved new values it will be
* hidden to avoid repeating messages already shown in the default error
* reporting after submission. This is useful to show general errors like
* missing settings when the user arrives at the settings page.
* @since 5.3.0 Legacy `error` and `updated` CSS classes are mapped to
* `notice-error` and `notice-success`.
* @param string $setting Optional slug title of a specific setting whose errors you want.
* @param bool $sanitize Whether to re-sanitize the setting value before returning errors.
* @param bool $hide_on_update If set to true errors will not be shown if the settings page has
* already been submitted.
function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) ) {
$settings_errors = get_settings_errors( $setting, $sanitize );
if ( empty( $settings_errors ) ) {
foreach ( $settings_errors as $key => $details ) {
if ( 'updated' === $details['type'] ) {
$details['type'] = 'success';
if ( in_array( $details['type'], array( 'error', 'success', 'warning', 'info' ), true ) ) {
$details['type'] = 'notice-' . $details['type'];