首页>建站相关>利用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-04-07

wordpress主题目录穿越导致的bug

尝试从知乎的热榜api提取数据并保存到本地,隔几个小时刷新一次,前几天运行的好好的,这几天突然发现数据有几天没有更新了。手动刷新了一下数据获取页,一直提示无需更新,将文件下载到本地测试,功能又是完好的。开了wp的debug模式,修正了...

建站相关 wordpress

wordpress 2025-03-31

wordpress 重新生成缩略图

测试wp缩略图功能的时候不小心把所有的缩略图都删掉了,但保留了原图,不想一个个重新上传以生成缩略图,就使用了这段代码,注意生成成功之后,这段代码就可以删掉了。忽然想起之前钉钉宣传的某个功能,阅后即焚~~function regener...

建站相关 wordpress

wordpress 2025-03-29

WordPress的主循环与WP_Query

WordPress的主循环和WP_Query是主题开发中最重要的两个概念,它们负责从数据库获取内容并显示在页面上。主循环 (The Loop)主循环是WordPress用来显示文章的核心机制。它是一个PHP代码结构,用于遍历当前页面请...

建站相关 wordpress

wordpress 2025-03-22

在phpstudy中为wordpress开启伪静态

原文修改主题都是在服务器上一边在线修改一边调试,用上了phpstudy后才发现自己之前的方式有多没有效率。但测试设置固定链接的时候遇到了一个问题,就是设置前也无风雨也无晴,设置后统一返回404。这个问题之前尝试搭建站点的时候也遇到过,...

建站相关 wordpress

wordpress 2025-03-17

WordPress分页中遇到404错误:posts_per_page

这个问题可能更多为主题开发者所遇见,一款推向市场的主题一般都会几经测试,应该不容易到客户手中才发现这个问题。所以网络上的相关讨论不多,博主也是调试了几天才大致有了一些思路:后台的默认参数在wordpress的后台设置里,是可以设置归档...

建站相关 wordpress

wordpress 2025-03-14

WORDPRESS HEADER模块常用函数

在 WordPress 开发中,header.php 文件是主题的重要组成部分,用于定义网站的头部内容。以下是一些在 header.php 中常用的 WordPress 函数及其用途,如果嫌部分函数生成的默认模板不需要的元素过多,也可...

建站相关 wordpress

wordpress 2025-03-12

wordpress的前后台数据交换ajax

ajax是个耳熟能详的词儿,但因为有点儿复杂,博主一直是规避学习的,今天刚好碰到一个前台jquery向wp后台申请数据的问题。躲不过,那就慢慢调试吧。钩子wp的ajax还区分了用户,对于不同的用户(登录与否)采用不同的钩子,不过这里只...

建站相关 wordpress

wordpress 2025-03-07

WordPress中add_meta_box函数参数详解

add_meta_box 是 WordPress 中用于在后台编辑页面添加自定义元框(Meta Box)的函数。它允许开发者在文章、页面、自定义文章类型等编辑页面中添加自定义字段或内容。以下是 add_meta_box 函数的参数及其...

建站相关 wordpress

wordpress 2025-03-07

wordpress 手动添加自定义字段

自定义字段可以扩展文章的信息,也有很多相关的成熟的插件,比如Advanced Custom Fields (ACF) 插件,如果希望添加的字段不多,也不愿意为此安装过多的插件,我们也可以考虑手动来添加它。为post文章添加字段// 添...

建站相关 wordpress