首页>建站相关>利用WordPress Settings API制作主题设置页

利用WordPress Settings API制作主题设置页

关于WordPress设置API

在WordPress v2.7中添加了设置API,它允许开发人员创建管理选项页面。界面风格与WordPress后台风格保持一致,只是它使用起来并不那么简单。你不能只定义一个设置数组,您需要编写自己的字段并保存方法。

首先注册一个设置页

视菜单位置的不同,我们需要自行选择命令,比如:

add_menu_page
add_submenu_page
add_theme_page

下面这个案例选择了使用add_menu_page,而这个设置项会出现在后台主菜单上;

/**
 * Add a new options page named "My Options".
 */
function myprefix_register_options_page() {
    add_menu_page(
        'My Options',
        'My Options',
        'manage_options',
        'my_options',
        'my_options_page_html'
    );
}
add_action( 'admin_menu', 'myprefix_register_options_page' );

/**
 * The "My Options" page html.
 */
function my_options_page_html() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    if ( isset( $_GET['settings-updated'] ) ) {
        add_settings_error(
            'my_options_mesages',
            'my_options_message',
            esc_html__( 'Settings Saved', 'text_domain' ),
            'updated'
        );
    }

    settings_errors( 'my_options_mesages' );

    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action="options.php" method="post">
            <?php
                settings_fields( 'my_options_group' );
                do_settings_sections( 'my_options' );
                submit_button( 'Save Settings' );
            ?>
        </form>
    </div>
    <?php
}

注册与添加设置项

这里的案例展现了一个数组类型的设置项的创建,我们创建一个设置项,然后将其作为一个数组,设置项目较多的时候,数组形式感觉更易于管理,也不容易让options变得臃肿。首先我们注册设置项:

/**
 * Register our settings.
 */
function myprefix_register_settings() {
    register_setting( 'my_options_group', 'my_options' );
}
add_action( 'admin_init', 'myprefix_register_settings' );

添加设置项元素,my_options是数组名,而my_option_1则是其中的一个数组成员;

/**
 * Register our settings.
 */
function myprefix_register_settings() {
    register_setting( 'my_options', 'my_options' );

    add_settings_section(
        'my_options_sections',
        false,
        false,
        'my_options'
    );

    add_settings_field(
        'my_option_1',
        esc_html__( 'My Option 1', 'text_domain' ),
        'render_my_option_1_field',
        'my_options',
        'my_options_sections',
        [
            'label_for' => 'my_option_1',
        ]
    );
}
add_action( 'admin_init', 'myprefix_register_settings' );

数据成功设置之后,我们需要在面板上显示它,所以需要一个回调函数,这样在下次进入设置页的时候,您能很直观的看到当前的设置数据;

/**
 * Render the "my_option_1" field.
 */
function render_my_option_1_field( $args ) {
    $value = get_option( 'my_options' )[$args['label_for']] ?? '';
    ?>
    <input
        type="text"
        id="<?php echo esc_attr( $args['label_for'] ); ?>"
        name="my_options[<?php echo esc_attr( $args['label_for'] ); ?>]"
        value="<?php echo esc_attr( $value ); ?>">
    <p class="description"><?php esc_html_e( 'This is a description for our field.', 'text_domain' ); ?></p>
    <?php
}

清理用户输入

出于安全原因,对保存到数据库的数据进行清理总是很重要的。为此,我们要回到我们的register_setting函数并添加一些额外的参数:

register_setting( 'my_options_group', 'my_options', [
    'sanitize_callback' => 'my_options_sanitize_fields',
    'default'           => []
] );

用于清理数据的回调函数:

/**
 * Sanitize fields before adding to the database.
 */
function my_options_sanitize_fields( $value ) {
    $value = (array) $value;
    if ( ! empty( $value['my_option_1'] ) ) {
        $value['my_option_1'] = sanitize_text_field( $value['my_option_1'] );
    }
    return $value;
}

此函数在传递到数据库之前检查选项值,检查my_option_1是否存在并清理该值。如果您想将相同的消毒应用于选项组中的每个选项 (您的字段将被保存为数组),您可以这样做:

/**
 * Sanitize fields before adding to the database.
 */
function my_options_sanitize_fields( $value ) {
    return array_map( 'sanitize_text_field', $value );
}

如何获取保存的选项值

现在您知道如何在WordPress中创建自己的自定义选项面板,下一步是使用您的自定义选项值。这将使用get_option功能。示例:

$my_option_1 = get_option( 'my_options' )['my_option_1'] ?? '';

您可能会注意到这段代码很熟悉,这是因为我们在上面使用了类似的代码render_my_option_1_field函数来获取我们字段的当前值。您也可以考虑为您的选项创建一个包装函数。示例:

// Helper function for returning theme options.
function myprefix_get_option( $option_name = '', $default = '' ) {
    return get_option( 'my_options' )['my_option_1'] ?? $default;
}

// Usage.
$option_value = myprefix_get_option( 'my_option_1', 'default value' );

管理选项页面助手PHP类

下面的辅助类可以添加到您的主题或插件,可以用它来更方便得创建您的管理面板。建议将此代码放在您自己的文件中,并通过require_once加载。

class WPEX_Options_Panel {

    /**
     * Options panel arguments.
     */
    protected $args = [];

    /**
     * Options panel title.
     */
    protected $title = '';

    /**
     * Options panel slug.
     */
    protected $slug = '';

    /**
     * Option name to use for saving our options in the database.
     */
    protected $option_name = '';

    /**
     * Option group name.
     */
    protected $option_group_name = '';

    /**
     * User capability allowed to access the options page.
     */
    protected $user_capability = '';

    /**
     * Our array of settings.
     */
    protected $settings = [];

    /**
     * Our class constructor.
     */
    public function __construct( array $args, array $settings ) {
        $this->args              = $args;
        $this->settings          = $settings;
        $this->title             = $this->args['title'] ?? esc_html__( 'Options', 'text_domain' );
        $this->slug              = $this->args['slug'] ?? sanitize_key( $this->title );
        $this->option_name       = $this->args['option_name'] ?? sanitize_key( $this->title );
        $this->option_group_name = $this->option_name . '_group';
        $this->user_capability   = $args['user_capability'] ?? 'manage_options';

        add_action( 'admin_menu', [ $this, 'register_menu_page' ] );
        add_action( 'admin_init', [ $this, 'register_settings' ] );
    }

    /**
     * Register the new menu page.
     */
    public function register_menu_page() {
        add_menu_page(
            $this->title,
            $this->title,
            $this->user_capability,
            $this->slug,
            [ $this, 'render_options_page' ]
        );
    }

    /**
     * Register the settings.
     */
    public function register_settings() {
        register_setting( $this->option_group_name, $this->option_name, [
            'sanitize_callback' => [ $this, 'sanitize_fields' ],
            'default'           => $this->get_defaults(),
        ] );

        add_settings_section(
            $this->option_name . '_sections',
            false,
            false,
            $this->option_name
        );

        foreach ( $this->settings as $key => $args ) {
            $type = $args['type'] ?? 'text';
            $callback = "render_{$type}_field";
            if ( method_exists( $this, $callback ) ) {
                $tr_class = '';
                if ( array_key_exists( 'tab', $args ) ) {
                    $tr_class .= 'wpex-tab-item wpex-tab-item--' . sanitize_html_class( $args['tab'] );
                }
                add_settings_field(
                    $key,
                    $args['label'],
                    [ $this, $callback ],
                    $this->option_name,
                    $this->option_name . '_sections',
                    [
                        'label_for' => $key,
                        'class'     => $tr_class
                    ]
                );
            }
        }
    }

    /**
     * Saves our fields.
     */
    public function sanitize_fields( $value ) {
        $value = (array) $value;
        $new_value = [];
        foreach ( $this->settings as $key => $args ) {
            $field_type = $args['type'];
            $new_option_value = $value[$key] ?? '';
            if ( $new_option_value ) {
                $sanitize_callback = $args['sanitize_callback'] ?? $this->get_sanitize_callback_by_type( $field_type );
                $new_value[$key] = call_user_func( $sanitize_callback, $new_option_value, $args );
            } elseif ( 'checkbox' === $field_type ) {
                $new_value[$key] = 0;
            }
        }
        return $new_value;
    }

    /**
     * Returns sanitize callback based on field type.
     */
    protected function get_sanitize_callback_by_type( $field_type ) {
        switch ( $field_type ) {
            case 'select':
                return [ $this, 'sanitize_select_field' ];
                break;
            case 'textarea':
                return 'wp_kses_post';
                break;
            case 'checkbox':
                return [ $this, 'sanitize_checkbox_field' ];
                break;
            default:
            case 'text':
                return 'sanitize_text_field';
                break;
        }
    }

    /**
     * Returns default values.
     */
    protected function get_defaults() {
        $defaults = [];
        foreach ( $this->settings as $key => $args ) {
            $defaults[$key] = $args['default'] ?? '';
        }
        return $defaults;
    }

    /**
     * Sanitizes the checkbox field.
     */
    protected function sanitize_checkbox_field( $value = '', $field_args = [] ) {
        return ( 'on' === $value ) ? 1 : 0;
    }

     /**
     * Sanitizes the select field.
     */
    protected function sanitize_select_field( $value = '', $field_args = [] ) {
        $choices = $field_args['choices'] ?? [];
        if ( array_key_exists( $value, $choices ) ) {
            return $value;
        }
    }

    /**
     * Renders the options page.
     */
    public function render_options_page() {
        if ( ! current_user_can( $this->user_capability ) ) {
            return;
        }

        if ( isset( $_GET['settings-updated'] ) ) {
            add_settings_error(
               $this->option_name . '_mesages',
               $this->option_name . '_message',
               esc_html__( 'Settings Saved', 'text_domain' ),
               'updated'
            );
        }

        settings_errors( $this->option_name . '_mesages' );

        ?>
        <div class="wrap">
            <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
            <?php $this->render_tabs(); ?>
            <form action="options.php" method="post" class="wpex-options-form">
                <?php
                    settings_fields( $this->option_group_name );
                    do_settings_sections( $this->option_name );
                    submit_button( 'Save Settings' );
                ?>
            </form>
        </div>
        <?php
    }

    /**
     * Renders options page tabs.
     */
    protected function render_tabs() {
        if ( empty( $this->args['tabs'] ) ) {
            return;
        }

        $tabs = $this->args['tabs'];
        ?>

        <style>.wpex-tab-item{ display: none; ?></style>

        <h2 class="nav-tab-wrapper wpex-tabs"><?php
            $first_tab = true;
            foreach ( $tabs as $id => $label ) {?>
                <a href="#" data-tab="<?php echo esc_attr( $id ); ?>" class="nav-tab<?php echo ( $first_tab ) ? ' nav-tab-active' : ''; ?>"><?php echo ucfirst( $label ); ?></a>
                <?php
                $first_tab = false;
            }
        ?></h2>

        <script>
            ( function() {
                document.addEventListener( 'click', ( event ) => {
                    const target = event.target;
                    if ( ! target.closest( '.wpex-tabs a' ) ) {
                        return;
                    }
                    event.preventDefault();
                    document.querySelectorAll( '.wpex-tabs a' ).forEach( ( tablink ) => {
                        tablink.classList.remove( 'nav-tab-active' );
                    } );
                    target.classList.add( 'nav-tab-active' );
                    targetTab = target.getAttribute( 'data-tab' );
                    document.querySelectorAll( '.wpex-options-form .wpex-tab-item' ).forEach( ( item ) => {
                        if ( item.classList.contains( `wpex-tab-item--${targetTab}` ) ) {
                            item.style.display = 'block';
                        } else {
                            item.style.display = 'none';
                        }
                    } );
                } );
                document.addEventListener( 'DOMContentLoaded', function () {
                    document.querySelector( '.wpex-tabs .nav-tab' ).click();
                }, false );
            } )();
        </script>

        <?php
    }

    /**
     * Returns an option value.
     */
    protected function get_option_value( $option_name ) {
        $option = get_option( $this->option_name );
        if ( ! array_key_exists( $option_name, $option ) ) {
            return array_key_exists( 'default', $this->settings[$option_name] ) ? $this->settings[$option_name]['default'] : '';
        }
        return $option[$option_name];
    }

    /**
     * Renders a text field.
     */
    public function render_text_field( $args ) {
        $option_name = $args['label_for'];
        $value       = $this->get_option_value( $option_name );
        $description = $this->settings[$option_name]['description'] ?? '';
        ?>
            <input
                type="text"
                id="<?php echo esc_attr( $args['label_for'] ); ?>"
                name="<?php echo $this->option_name; ?>[<?php echo esc_attr( $args['label_for'] ); ?>]"
                value="<?php echo esc_attr( $value ); ?>">
            <?php if ( $description ) { ?>
                <p class="description"><?php echo esc_html( $description ); ?></p>
            <?php } ?>
        <?php
    }

    /**
     * Renders a textarea field.
     */
    public function render_textarea_field( $args ) {
        $option_name = $args['label_for'];
        $value       = $this->get_option_value( $option_name );
        $description = $this->settings[$option_name]['description'] ?? '';
        $rows        = $this->settings[$option_name]['rows'] ?? '4';
        $cols        = $this->settings[$option_name]['cols'] ?? '50';
        ?>
            <textarea
                type="text"
                id="<?php echo esc_attr( $args['label_for'] ); ?>"
                rows="<?php echo esc_attr( absint( $rows ) ); ?>"
                cols="<?php echo esc_attr( absint( $cols ) ); ?>"
                name="<?php echo $this->option_name; ?>[<?php echo esc_attr( $args['label_for'] ); ?>]"><?php echo esc_attr( $value ); ?></textarea>
            <?php if ( $description ) { ?>
                <p class="description"><?php echo esc_html( $description ); ?></p>
            <?php } ?>
        <?php
    }

    /**
     * Renders a checkbox field.
     */
    public function render_checkbox_field( $args ) {
        $option_name = $args['label_for'];
        $value       = $this->get_option_value( $option_name );
        $description = $this->settings[$option_name]['description'] ?? '';
        ?>
            <input
                type="checkbox"
                id="<?php echo esc_attr( $args['label_for'] ); ?>"
                name="<?php echo $this->option_name; ?>[<?php echo esc_attr( $args['label_for'] ); ?>]"
                <?php checked( $value, 1, true ); ?>
            >
            <?php if ( $description ) { ?>
                <p class="description"><?php echo esc_html( $description ); ?></p>
            <?php } ?>
        <?php
    }

    /**
     * Renders a select field.
     */
    public function render_select_field( $args ) {
        $option_name = $args['label_for'];
        $value       = $this->get_option_value( $option_name );
        $description = $this->settings[$option_name]['description'] ?? '';
        $choices     = $this->settings[$option_name]['choices'] ?? [];
        ?>
            <select
                id="<?php echo esc_attr( $args['label_for'] ); ?>"
                name="<?php echo $this->option_name; ?>[<?php echo esc_attr( $args['label_for'] ); ?>]"
            >
                <?php foreach ( $choices as $choice_v => $label ) { ?>
                    <option value="<?php echo esc_attr( $choice_v ); ?>" <?php selected( $choice_v, $value, true ); ?>><?php echo esc_html( $label ); ?></option>
                <?php } ?>
            </select>
            <?php if ( $description ) { ?>
                <p class="description"><?php echo esc_html( $description ); ?></p>
            <?php } ?>
        <?php
    }

}

使用示例

示例一

Creating_a_Theme_Settings_Page_Using_WordPress_Settings_API_p1

// Register new Options panel.
$panel_args = [
    'title'           => 'My Options',
    'option_name'     => 'my_options',
    'slug'            => 'my-options-panel',
    'user_capability' => 'manage_options',
];

$panel_settings = [
    'option_1' => [
        'label'       => esc_html__( 'Checkbox Option', 'text_domain' ),
        'type'        => 'checkbox',
        'description' => 'My checkbox field description.',
    ],
    'option_2' => [
        'label'       => esc_html__( 'Select Option', 'text_domain' ),
        'type'        => 'select',
        'description' => 'My select field description.',
        'choices'     => [
            ''         => esc_html__( 'Select', 'text_domain' ),
            'choice_1' => esc_html__( 'Choice 1', 'text_domain' ),
            'choice_2' => esc_html__( 'Choice 2', 'text_domain' ),
            'choice_3' => esc_html__( 'Choice 3', 'text_domain' ),
        ],
    ],
    'option_3' => [
        'label'       => esc_html__( 'Text Option', 'text_domain' ),
        'type'        => 'text',
        'description' => 'My field 1 description.',
    ],
    'option_4' => [
        'label'       => esc_html__( 'Textarea Option', 'text_domain' ),
        'type'        => 'textarea',
        'description' => 'My textarea field description.',
    ],
];

new WPEX_Options_Panel( $panel_args, $panel_settings );

示例二

Creating_a_Theme_Settings_Page_Using_WordPress_Settings_API_p2

// Register new Options panel.
$panel_args = [
    'title'           => 'My Options',
    'option_name'     => 'my_options',
    'slug'            => 'my-options-panel',
    'user_capability' => 'manage_options',
    'tabs'            => [
        'tab-1' => esc_html__( 'Tab 1', 'text_domain' ),
        'tab-2' => esc_html__( 'Tab 2', 'text_domain' ),
    ],
];

$panel_settings = [
    // Tab 1
    'option_1' => [
        'label'       => esc_html__( 'Checkbox Option', 'text_domain' ),
        'type'        => 'checkbox',
        'description' => 'My checkbox field description.',
        'tab'         => 'tab-1',
    ],
    'option_2' => [
        'label'       => esc_html__( 'Select Option', 'text_domain' ),
        'type'        => 'select',
        'description' => 'My select field description.',
        'choices'     => [
            ''         => esc_html__( 'Select', 'text_domain' ),
            'choice_1' => esc_html__( 'Choice 1', 'text_domain' ),
            'choice_2' => esc_html__( 'Choice 2', 'text_domain' ),
            'choice_3' => esc_html__( 'Choice 3', 'text_domain' ),
        ],
        'tab'         => 'tab-1',
    ],
    // Tab 2
    'option_3' => [
        'label'       => esc_html__( 'Text Option', 'text_domain' ),
        'type'        => 'text',
        'description' => 'My field 1 description.',
        'tab'         => 'tab-2',
    ],
    'option_4' => [
        'label'       => esc_html__( 'Textarea Option', 'text_domain' ),
        'type'        => 'textarea',
        'description' => 'My textarea field description.',
        'tab'         => 'tab-2',
    ],
];

new WPEX_Options_Panel( $panel_args, $panel_settings );

本文系转载,作者为AJ Clarke,以下是原文链接:

https://www.wpexplorer.com/wordpress-theme-options/

标签: wordpress

移动端可扫我直达哦~

推荐阅读

wordpress 2025-01-13

woocommerce历史版本下载页

WooCommerce是一个开源的电子商务插件,专为WordPress网站设计,允许用户在其网站上创建和管理在线商店。自2011年推出以来,WooCommerce迅速成为全球最受欢迎的电商解决方案之一。https://develope...

建站相关 wordpress

wordpress 2025-01-13

关于wp_get_nav_menu_items()这个函数

自己手动书写css的情况,wp的wp_nav_menu()会提供一套分工明确的类,根据其默认类适配css基本就够用了。但应用一些其他框架的时候,不同框架的类名定义显然是不一致的,这个时候wp_nav_menu()提供的自定义功能就有些...

建站相关 wordpress

wordpress 2025-01-10

Wordpress主题中的单例模式

其实对于博主这样的初学者,这个话题是有点超纲的,但如果从零开始想做一个主题。观摩一些成熟的主题是必不可少的,这个时候就有可能遇到这种单例模式的写法,所以即便我们暂时用不到,但了解一下结构,多少能看明白这个类究竟在做些什么事情。单例模式...

建站相关 wordpress

wordpress 2025-01-06

Wordpress主题开发笔记之三 wp_head()

WordPress主题或插件都可以通过给wp_head()函数来向网站的head标签中加入内容,这个函数经常会和wp_footer()函数一起出现,顾名思义,wp_footer()负责在站点的尾部插入内容,这是官方推荐的引入资源的方式...

建站相关 wordpress

wordpress 2025-01-03

Wordpress主题开发笔记之零 劝退函数列表

在ytkah大佬的博客里看到了这个列表,原文地址如下,复制进excel表格内发现一共有951项(含中文小标题),粗略估计有900来个函数吧。当然这并不是Wordpress函数的全貌,但单这900多个函数中的部分函数,可能很多人终其职业...

建站相关 wordpress

wordpress 2024-12-26

从零开始做一个wordpress主题系列

一直想DIY一个wordpress主题,虽然梦想还是要有的,但念念不忘,至今也没有什么回响。博客里倒是攒了几篇相关的文章,眼瞅着孩子快放寒假,假期不再需要迎来送往,可能会空一点,就准备整理一下,顺便重拾这份初心。因为是随手做的笔记,所...

建站相关 wordpress

wordpress 2024-12-26

创建自定义WordPress主题设置页面

WordPress以其灵活性和易用性而闻名,使其成为各种规模网站的热门选择。有助于其灵活性的关键功能之一是能够为您的主题创建自定义设置页面。这使您可以为用户提供一个界面,以自定义主题的各个方面,而无需深入代码。为什么要创建自定义设置页...

建站相关 wordpress

wordpress 2024-12-25

如何重新安装一个wordpress

拖拖拉拉的,到今天为止,虾比比分站也才一个首页。倒是待审广告评论已经累计了2000多条,懒得一条条删除,干脆重新安装一下系统。首先进入数据库,删除掉原来博客对应的数据表。drop database yourdatabase接下来在对应...

建站相关 wordpress