错误:找不到选项页-正在保存带有选项卡的设置页

时间:2019-07-08 作者:Ryszard Jędraszyk

我正在努力让用WordPress设置API创建的选项卡式插件设置正常工作。

第一个选项卡正确保存设置。但是,每次我单击任何其他选项卡的“保存更改”按钮时,都会出现一个白色屏幕,其中显示以下错误:

错误:找不到选项页

Chrome和Apache日志显示POST 500错误。我发现要提交的表单数据似乎是正确的,并且符合为第一个有效选项卡提交的内容general_section :

option_page: account_section
action: update
_wpnonce: 2d40b0a357
_wp_http_referer: /staging/wp-admin/options-general.php?page=woo-extra-settings&tab=account
eswc_settingz[eswc_redirect]: 1
submit: Save Changes
只有选择了正确的选项卡,才能注册这些字段,以避免在保存时将其他选项卡中的值重置为默认值。

本主题中的代码包含在我的示例中,但没有解决问题:

"Error: Options Page Not Found" on Settings Page Submission for an OOP Plugin

我为Chrome使用PHP控制台扩展,并使用插件将值打印到Chrome控制台以进行故障排除,例如:

PC::debug(  \'general\', \'tab name\' );
现在对此进行了评论。该代码可以作为我插件的一部分,在默认的“设置”菜单中生成一个两个选项卡的设置页面,并重现我遇到的问题。

在选项卡激活时,控制台返回以下值(whitelist_custom_options_page 函数不执行):

“常规”(第一个选项卡):

tab name:  general
add settings section - page:  woo-extra-settings
add settings section - id:  general_section
“账户”(第二个选项卡)

tab name:  account
add settings section - page:  woo-extra-settings
add settings section - id:  account_section
保存设置时,值为:

“常规”(第一个选项卡):

tab name:  general
add settings section - page:  woo-extra-settings
add settings section - id:  general_section
whitelist page:  woo-extra-settings
whitelist section:  general_section
whitelist option:  eswc_settingz
对于“Account”(第二个选项卡),值都是相同的,这意味着在保存设置时,我的代码错误地将任何选项卡视为第一个选项卡,我遇到问题的原因是什么。

如何以接近当前实现的方式解决此问题?

代码如下:

class extra_settings_settings {

private $options;
private $settings_page_name;
private $settings_menu_name;

public function __construct() {

    if ( is_admin() ) {

        $this->settings_page_name = \'woo-extra-settings\';
        $this->settings_menu_name = \'Woo Extra Settings\';

        // Tracks new sections for whitelist_custom_options_page()
        $this->page_sections = array();
        // Must run after option_update_filter(), so priority > 10
        add_action( \'whitelist_options\', array( $this, \'whitelist_custom_options_page\' ),11 );          

        // Initialize and register settings. 
        add_action( \'admin_init\', array( $this, \'display_options\' ) );
        // Add settings page.
        add_action( \'admin_menu\', array( $this, \'add_settings_page\' ) );    

    }
}

public function display_options() {
    $active_tab = isset( $_GET[ \'tab\' ] ) ? $_GET[ \'tab\' ] : \'general\';
    if ( $active_tab == \'general\' ) {
        //PC::debug(  \'general\', \'tab name:\' );
        register_setting( \'general_section\', \'eswc_settingz\', array( $this, \'sanitize_general\' ) );
        // ID / title / cb / page       
        $this->add_settings_section( \'general_section\', null, array( $this, \'general_section_cb\' ), $this->settings_page_name );
        // ID / title / cb / page / section /args
        add_settings_field( \'eswc_kill_gutenberg\', __( \'Gutenberg\', \'extra-settings-for-woocommerce\' ), array( $this, \'eswc_kill_gutenberg_cb\' ), $this->settings_page_name, \'general_section\' );
        add_settings_field( \'eswc_change_email_author\', __( \'WP core email author\', \'extra-settings-for-woocommerce\' ), array( $this, \'eswc_change_email_author_cb\' ), $this->settings_page_name, \'general_section\' );
    } else if ( $active_tab == \'account\' ) {
        //PC::debug(  \'account\', \'tab name:\' );
        register_setting( \'account_section\', \'eswc_settingz\', array( $this, \'sanitize_account\' ) );
        $this->add_settings_section( \'account_section\', null, array( $this, \'account_section_cb\' ), $this->settings_page_name );
        add_settings_field( \'eswc_redirect\', __( \'Login redirect\', \'extra-settings-for-woocommerce\' ), array( $this, \'eswc_redirect_cb\' ), $this->settings_page_name, \'account_section\' );      
    }
}

  public function add_settings_page() {
    // This page will be under "Settings"
    $this->plugin_hook_suffix = add_options_page(
        \'Settings Admin\', $this->settings_menu_name, \'manage_options\', $this->settings_page_name, array( $this, \'create_settings_page\' )
    );
}

// Wrapper for wp\'s `add_settings_section()` that tracks custom sections
private function add_settings_section( $id, $title, $cb, $page ){
    add_settings_section( $id, $title, $cb, $page );                
    if( $id != $page ){
        if( !isset($this->page_sections[$page]))
            //PC::debug(  $page, \'add settings section - page:\' );
            //PC::debug(  $id, \'add settings section - id:\' );  
            $this->page_sections[$page] = array();
        $this->page_sections[$page][$id] = $id;     
    }
}   

// White-lists options on custom pages.
public function whitelist_custom_options_page( $whitelist_options ){
    // Custom options are mapped by section id; Re-map by page slug.
    foreach($this->page_sections as $page => $sections ){           
        //PC::debug(  $page, \'whitelist page:\' );           
        $whitelist_options[$page] = array();
        foreach( $sections as $section )            
            //PC::debug(  $section, \'whitelist section:\' );         
            if( !empty( $whitelist_options[$section] ) )
                foreach( $whitelist_options[$section] as $option )
                    $whitelist_options[$page][] = $option;                      
                    //PC::debug(  $option, \'whitelist option:\' );
            }
    return $whitelist_options;
}

/**
 * Get the option that is saved or the default.
 *
 * @param string $index. The option we want to get.
 */
public function eswc_get_settings( $index = false ) {

    $defaults = array ( \'eswc_kill_gutenberg\' => false, \'eswc_change_email_author\' => false, \'eswc_redirect\' => false);
    $settings = get_option( \'eswc_settingz\', $defaults );

    if ( $index && isset( $settings[ $index ] ) ) {
        return $settings[ $index ];
    }

    return $settings;
}

public function create_settings_page() {

    $this->options = $this->eswc_get_settings();

    ?>
    <div class="wrap">
        <h1>Extra Settings For WooCommerce</h1>
        <?php
        $active_tab = isset( $_GET[ \'tab\' ] ) ? $_GET[ \'tab\' ] : \'general\';         
        ?>
        <h2 class="nav-tab-wrapper">
            <a href="?page=woo-extra-settings&tab=general" class="nav-tab <?php echo $active_tab == \'general\' ? \'nav-tab-active\' : \'\'; ?>">General</a>
            <a href="?page=woo-extra-settings&tab=account" class="nav-tab <?php echo $active_tab == \'account\' ? \'nav-tab-active\' : \'\'; ?>">Account</a>          
        <form method="post" action="options.php">
        <?php
            // Output nonce, action, and option_page fields for a settings page.
            if( $active_tab == \'general\' ) {
                settings_fields( \'general_section\' );               
                echo \'<table class="form-table">\';
                do_settings_fields ($this->settings_page_name, \'general_section\');
                echo \'</table>\';
            } else if ( $active_tab == \'account\' ){
                settings_fields( \'account_section\' );               
                echo \'<table class="form-table">\';
                do_settings_fields ($this->settings_page_name, \'account_section\');
                echo \'</table>\';
            }

            submit_button();
        ?>
        </form>
    </div>
    <?php
}

/**
 * Sanitize each setting field as needed
 *
 * @param array $input Contains all settings fields as array keys
 */
public function sanitize_general( $input ) {
    $new_input = array();
    if( isset( $input[\'eswc_kill_gutenberg\'] ) )
        $new_input[\'eswc_kill_gutenberg\'] = ( $input[\'eswc_kill_gutenberg\'] == 1 ? 1 : 0 );
    if( isset( $input[\'eswc_change_email_author\'] ) )
        $new_input[\'eswc_change_email_author\'] = ( $input[\'eswc_change_email_author\'] == 1 ? 1 : 0 );       
    return $new_input;
}

public function sanitize_account( $input ) {
    $new_input = array();
    if( isset( $input[\'eswc_redirect\'] ) )
        $new_input[\'eswc_redirect\'] = ( $input[\'eswc_redirect\'] == 1 ? 1 : 0 );
    return $new_input;
}

/** 
 * Get the settings option array and print one of its values
 */

public function eswc_kill_gutenberg_cb() {
    printf(
    \'<fieldset>
        <label><input id="eswc_kill_gutenberg" type="checkbox" name="eswc_settingz[eswc_kill_gutenberg]" value="1" %1$s />%2$s</label>
    </fieldset>\',           
    isset( $this->options[\'eswc_kill_gutenberg\'] ) && ( 1 == $this->options[\'eswc_kill_gutenberg\'] )  ? \'checked="checked" \':\'\',
    __( \'Disable Gutenberg editor. Don\\\'t load Gutenberg-related stylesheets from WordPress core, WooCommerce and Storefront.\', \'extra-settings-for-woocommerce\' )      
    );
}

public function eswc_change_email_author_cb() {
    printf(
    \'<fieldset>
        <label><input id="eswc_change_email_author" type="checkbox" name="eswc_settingz[eswc_change_email_author]" value="1" %1$s />%2$s</label>
    </fieldset>\',           
    isset( $this->options[\'eswc_change_email_author\'] ) && ( 1 == $this->options[\'eswc_change_email_author\'] )  ? \'checked="checked" \':\'\',
    __( \'Default is WordPress, wordpress@yourdomain.com. Change to: "Site Title" from Settings > General, custom email entered below.\', \'extra-settings-for-woocommerce\' )      
    );
}   

public function eswc_redirect_cb() {
    printf(
    \'<fieldset>
        <label><input id="eswc_redirect" type="checkbox" name="eswc_settingz[eswc_redirect]" value="1" %1$s />%2$s</label>
    </fieldset>
    <p class="description">%3$s</p>\',           
    isset( $this->options[\'eswc_redirect\'] ) && ( 1 == $this->options[\'eswc_redirect\'] )  ? \'checked="checked" \':\'\',
    __( \'After a successful login, redirect customers to previously visited page and users with admin access to dashboard.\', \'extra-settings-for-woocommerce\' ),
    __( \'By default WooCommerce redirects to "My account" page. Customer roles: customer, subscriber. Admin access roles: administrator, shop_manager, editor, author, contributor.\', \'extra-settings-for-woocommerce\' )
    );
}   
}

$eswc_settingz_page = new extra_settings_settings();

2 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

首先,只有选择了正确的选项卡,才能注册字段,以避免在保存时将其他选项卡中的值重置为默认值。

因此,您应该向wp-admin/options.php 表单提交到的页面。

您只需将其作为查询字符串传递到表单中action 属性值:

<form method="post" action="<?php echo esc_url( add_query_arg( // wrapped for clarity
  \'tab\', $active_tab, admin_url( \'options.php\' )
) ); ?>">
create_settings_page(), 添加一个隐藏的输入字段,该字段的值为tab slug:

echo \'<input type="hidden" name="tab" value="\' . esc_attr( $active_tab ) . \'" />\';
submit_button();
然后在display_options(), 使用检索选项卡段塞$_REQUEST:

$active_tab = isset( $_REQUEST[\'tab\'] ) ? $_REQUEST[\'tab\'] : \'general\';
无论哪种方式,关键是register_setting() 中的调用display_options() 被调用。否则,WordPress会抛出“找不到选项页”错误,因为选项页未注册。

您可以使用whitelist_options 过滤器,但我更希望register_setting() 调用,所以我删除了这个和相关的回调(whitelist_custom_options_page()):

add_action( \'whitelist_options\', array( $this, \'whitelist_custom_options_page\' ),11 );
第二件事,因为您使用的是相同的数据库选项名称(eswc_settingz) 对于所有选项卡/字段,应将保存的数据与提交的数据合并:

public function sanitize_general( $input ) {
    $new_input = (array) get_option( \'eswc_settingz\' ); // get saved data
    ... add/update new data
    return $new_input;
}

public function sanitize_account( $input ) {
    $new_input = (array) get_option( \'eswc_settingz\' ); // get saved data
    ... add/update new data
    return $new_input;
}
或者可以使用不同的数据库选项名称:

register_setting( \'general_section\', \'eswc_general_settingz\', array( $this, \'sanitize_general\' ) );
register_setting( \'account_section\', \'eswc_account_settingz\', array( $this, \'sanitize_account\' ) );
顺便问一下,是不是settingz 打字错误?也许是命中注定的settings?...

SO网友:Ryszard Jędraszyk

Sally CJ的解决方案完美地解决了我遇到的问题,但在这个实现中出现了一个新问题。

将当前选项卡中的设置与所有现有数据库设置合并(eswc_settingz) 通过这种方式$new_input 数组填充了所有设置,而不是像以前一样为空。isset( $input[\'eswc_redirect\'] 退货false 如果复选框未选中。以前,它会导致提交一个空的数组项,数据库会将复选框视为未选中。现在,由于此项已经填充了数据库值,它还必须将0(未选中)复选框状态保存到数组中,所以我添加了else 声明:

public function sanitize_account( $input ) {
    // $new_input = (array) get_option( \'eswc_settingz\' );
    $new_input = $this->eswc_get_settings();
    if( isset( $input[\'eswc_redirect\'] ) ) {
        $new_input[\'eswc_redirect\'] = ( $input[\'eswc_redirect\'] == 1 ? 1 : 0 );
    } else {
        $new_input[\'eswc_redirect\'] = 0;
    }
    return $new_input;
}
编辑:

为了使用我的函数,我注释掉了一行,并将其替换为下面的一行eswc_get_settings 将现有数据库设置与默认值数组合并。

相关推荐