"Помилка: Сторінка параметрів не знайдена" на сторінці налаштування для надсилання плагіна OOP


19

Я розробляю плагін, використовуючи сховище Тома МакФарліна Boilerplate як шаблон, який використовує практики OOP. Я намагався з'ясувати, чому я не можу правильно надіслати свої налаштування. Я спробував встановити атрибут дії на порожній рядок, як було запропоновано в іншому питанні, але це не допомогло ...

Нижче наведено загальну настройку коду, яку я використовую ...

Форма (/views/admin.php):

<div class="wrap">
    <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
    <form action="options.php" method="post">
        <?php
        settings_fields( $this->plugin_slug );
        do_settings_sections( $this->plugin_slug );
        submit_button( 'Save Settings' );
        ?>
    </form>
</div>

Для наступного коду припустімо, що всі зворотні виклики для add_settings_field () та add_settings_section () існують, за винятком 'option_list_selection'.

Клас адміністратора плагінів (/ {plugin_name} -class-admin.php):

namespace wp_plugin_name;

class Plugin_Name_Admin
{
    /**
     * Note: Some portions of the class code and method functions are missing for brevity
     * Let me know if you need more information...
     */

    private function __construct()
    {
        $plugin              = Plugin_Name::get_instance();

        $this->plugin_slug   = $plugin->get_plugin_slug();
        $this->friendly_name = $plugin->get_name(); // Get "Human Friendly" presentable name

        // Adds all of the options for the administrative settings
        add_action( 'admin_init', array( $this, 'plugin_options_init' ) );

        // Add the options page and menu item
        add_action( 'admin_menu', array( $this, 'add_plugin_admin_menu' ) );


    }

    public function add_plugin_admin_menu()
    {

        // Add an Options Page
        $this->plugin_screen_hook_suffix =
        add_options_page(
            __( $this->friendly_name . " Options", $this->plugin_slug ),
            __( $this->friendly_name, $this->plugin_slug ),
            "manage_options", 
            $this->plugin_slug,
            array( $this, "display_plugin_admin_page" )
        );

    }

    public function display_plugin_admin_page()
    {
        include_once( 'views/admin.php' );
    }

    public function plugin_options_init()
    {
        // Update Settings
        add_settings_section(
            'maintenance',
            'Maintenance',
            array( $this, 'maintenance_section' ),
            $this->plugin_slug
        );

        // Check Updates Option
        register_setting( 
            'maintenance',
            'plugin-name_check_updates',
            'wp_plugin_name\validate_bool'
        );

        add_settings_field(
            'check_updates',
            'Should ' . $this->friendly_name . ' Check For Updates?',
            array( $this, 'check_updates_field' ),
            $this->plugin_slug,
            'maintenance'
        );

        // Update Period Option
        register_setting(
            'maintenance',
            'plugin-name_update_period',
            'wp_plugin_name\validate_int'
        );

        add_settings_field(
            'update_frequency',
            'How Often Should ' . $this->friendly_name . ' Check for Updates?',
            array( $this, 'update_frequency_field' ),
            $this->plugin_slug,
            'maintenance'
        );

        // Plugin Option Configurations
        add_settings_section(
            'category-option-list', 'Widget Options List',
            array( $this, 'option_list_section' ),
            $this->plugin_slug
        );
    }
}

Деякі запитувані оновлення:

Зміна атрибуту дії на:

<form action="../../options.php" method="post">

... просто призводить до помилки 404. Далі нижче - уривок журналів Apache. Зауважте, що сценарії WordPress за замовчуванням та черги CSS видалено:

# Changed to ../../options.php
127.0.0.1 - - [01/Apr/2014:15:59:43 -0400] "GET /wp-admin/options-general.php?page=pluginname-widget HTTP/1.1" 200 18525
127.0.0.1 - - [01/Apr/2014:15:59:43 -0400] "GET /wp-content/plugins/PluginName/admin/assets/css/admin.css?ver=0.1.1 HTTP/1.1" 304 -
127.0.0.1 - - [01/Apr/2014:15:59:43 -0400] "GET /wp-content/plugins/PluginName/admin/assets/js/admin.js?ver=0.1.1 HTTP/1.1" 304 -
127.0.0.1 - - [01/Apr/2014:15:59:52 -0400] "POST /options.php HTTP/1.1" 404 1305
127.0.0.1 - - [01/Apr/2014:16:00:32 -0400] "POST /options.php HTTP/1.1" 404 1305

#Changed to options.php
127.0.0.1 - - [01/Apr/2014:16:00:35 -0400] "GET /wp-admin/options-general.php?page=pluginname-widget HTTP/1.1" 200 18519
127.0.0.1 - - [01/Apr/2014:16:00:35 -0400] "GET /wp-content/plugins/PluginName/admin/assets/css/admin.css?ver=0.1.1 HTTP/1.1" 304 -
127.0.0.1 - - [01/Apr/2014:16:00:35 -0400] "GET /wp-content/plugins/PluginName/admin/assets/js/admin.js?ver=0.1.1 HTTP/1.1" 304 -
127.0.0.1 - - [01/Apr/2014:16:00:38 -0400] "POST /wp-admin/options.php HTTP/1.1" 500 2958

І файл php-errors.log, і файл debug.log, коли WP_DEBUG вірно, порожні.

Клас плагінів (/{plugin-name}-class.php)

namespace wp_plugin_name;

class Plugin_Name
{
    const VERSION = '1.1.2';
    const TABLE_VERSION = 1;
    const CHECK_UPDATE_DEFAULT = 1;
    const UPDATE_PERIOD_DEFAULT = 604800;

    protected $plugin_slug = 'pluginname-widget';
    protected $friendly_name = 'PluginName Widget';

    protected static $instance = null;

    private function __construct()
    {

        // Load plugin text domain
        add_action( 'init',
                    array(
            $this,
            'load_plugin_textdomain' ) );

        // Activate plugin when new blog is added
        add_action( 'wpmu_new_blog',
                    array(
            $this,
            'activate_new_site' ) );

        // Load public-facing style sheet and JavaScript.
        add_action( 'wp_enqueue_scripts',
                    array(
            $this,
            'enqueue_styles' ) );
        add_action( 'wp_enqueue_scripts',
                    array(
            $this,
            'enqueue_scripts' ) );

        /* Define custom functionality.
         * Refer To http://codex.wordpress.org/Plugin_API#Hooks.2C_Actions_and_Filters
         */

    }

    public function get_plugin_slug()
    {
        return $this->plugin_slug;
    }

    public function get_name()
    {
        return $this->friendly_name;
    }

    public static function get_instance()
    {

        // If the single instance hasn't been set, set it now.
        if ( null == self::$instance )
        {
            self::$instance = new self;
        }

        return self::$instance;

    }

    /**
     * The member functions activate(), deactivate(), and update() are very similar.
     * See the Boilerplate plugin for more details...
     *
     */

    private static function single_activate()
    {
        if ( !current_user_can( 'activate_plugins' ) )
            return;

        $plugin_request = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';

        check_admin_referer( "activate-plugin_$plugin_request" );

        /**
         *  Test to see if this is a fresh installation
         */
        if ( get_option( 'plugin-name_version' ) === false )
        {
            // Get the time as a Unix Timestamp, and add one week
            $unix_time_utc = time() + Plugin_Name::UPDATE_PERIOD_DEFAULT;

            add_option( 'plugin-name_version', Plugin_Name::VERSION );
            add_option( 'plugin-name_check_updates',
                        Plugin_Name::CHECK_UPDATE_DEFAULT );
            add_option( 'plugin-name_update_frequency',
                        Plugin_Name::UPDATE_PERIOD_DEFAULT );
            add_option( 'plugin-name_next_check', $unix_time_utc );

            // Create options table
            table_update();

            // Let user know PluginName was installed successfully
            is_admin() && add_filter( 'gettext', 'finalization_message', 99, 3 );
        }
        else
        {
            // Let user know PluginName was activated successfully
            is_admin() && add_filter( 'gettext', 'activate_message', 99, 3 );
        }

    }

    private static function single_update()
    {
        if ( !current_user_can( 'activate_plugins' ) )
            return;

        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';

        check_admin_referer( "activate-plugin_{$plugin}" );

        $cache_plugin_version         = get_option( 'plugin-name_version' );
        $cache_table_version          = get_option( 'plugin-name_table_version' );
        $cache_deferred_admin_notices = get_option( 'plugin-name_admin_messages',
                                                    array() );

        /**
         * Find out what version of our plugin we're running and compare it to our
         * defined version here
         */
        if ( $cache_plugin_version > self::VERSION )
        {
            $cache_deferred_admin_notices[] = array(
                'error',
                "You seem to be attempting to revert to an older version of " . $this->get_name() . ". Reverting via the update feature is not supported."
            );
        }
        else if ( $cache_plugin_version === self::VERSION )
        {
            $cache_deferred_admin_notices[] = array(
                'updated',
                "You're already using the latest version of " . $this->get_name() . "!"
            );
            return;
        }

        /**
         * If we can't determine what version the table is at, update it...
         */
        if ( !is_int( $cache_table_version ) )
        {
            update_option( 'plugin-name_table_version', TABLE_VERSION );
            table_update();
        }

        /**
         * Otherwise, we'll just check if there's a needed update
         */
        else if ( $cache_table_version < TABLE_VERSION )
        {
            table_update();
        }

        /**
         * The table didn't need updating.
         * Note we cannot update any other options because we cannot assume they are still
         * the defaults for our plugin... ( unless we stored them in the db )
         */

    }

    private static function single_deactivate()
    {

        // Determine if the current user has the proper permissions
        if ( !current_user_can( 'activate_plugins' ) )
            return;

        // Is there any request data?
        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';

        // Check if the nonce was valid
        check_admin_referer( "deactivate-plugin_{$plugin}" );

        // We'll, technically the plugin isn't included when deactivated so...
        // Do nothing

    }

    public function load_plugin_textdomain()
    {

        $domain = $this->plugin_slug;
        $locale = apply_filters( 'plugin_locale', get_locale(), $domain );

        load_textdomain( $domain,
                         trailingslashit( WP_LANG_DIR ) . $domain . '/' . $domain . '-' . $locale . '.mo' );
        load_plugin_textdomain( $domain, FALSE,
                                basename( plugin_dir_path( dirname( __FILE__ ) ) ) . '/languages/' );

    }

    public function activate_message( $translated_text, $untranslated_text,
                                      $domain )
    {
        $old = "Plugin <strong>activated</strong>.";
        $new = FRIENDLY_NAME . " was  <strong>successfully activated</strong> ";

        if ( $untranslated_text === $old )
            $translated_text = $new;

        return $translated_text;

    }

    public function finalization_message( $translated_text, $untranslated_text,
                                          $domain )
    {
        $old = "Plugin <strong>activated</strong>.";
        $new = "Captain, The Core is stable and PluginName was <strong>successfully installed</strong> and ready for Warp speed";

        if ( $untranslated_text === $old )
            $translated_text = $new;

        return $translated_text;

    }

}

Список літератури:


В описі щедрості повідомляється: "Будь ласка, надайте трохи інформації про кращі практики " . Використання одинаків з приватними конструкторами та купа дій всередині них: погана практика та складна перевірка, проте не ваша вина.
gmazzap

1
використовуйте ../../options.php після тестування вашого коду.
ravi patel

Чи можете ви, будь ласка, показати get_plugin_slug ().
vancoder

@vancoder Я відредагував публікацію вище з відповідною інформацією ...
gate_engineer

Чому у ваших регістрах_настройки є зворотні косої риси зворотних викликів санітарії? Я не думаю, що це спрацювало б.
Бьорн

Відповіді:


21

Помилка "Помилка: Сторінка параметрів не знайдена"

Це відома проблема в API налаштувань WP. Був квиток відкриваються років тому, і вона була позначена як вирішена - але помилка НЕ усунена в останніх версіях WordPress. Ось що про це сказала (тепер видалена) сторінка Codex :

"Помилка: сторінка з параметрами не знайдена." Проблема (включаючи рішення та пояснення):

Проблема тоді полягає в тому, що фільтр "whitelist_options" не має потрібного індексу для ваших даних. Він застосовується на options.php # 98 (WP 3.4).

register_settings()додає ваші дані до глобальних $new_whitelist_options. Потім це об'єднується з глобальним $whitelist_optionsусередині зворотних ( option_update_filter()відповідних add_option_whitelist()) викликів. Ці зворотні дзвінки додають ваші дані в глобальний $new_whitelist_optionsз $option_groupіндексом "as". Коли ви стикаєтеся з "Помилка: сторінка з параметрами не знайдена." це означає, що ваш індекс не розпізнано Оманлива річ полягає в тому, що перший аргумент використовується як індекс та названий $options_group, коли фактична перевірка у options.php # 112 відбувається проти $options_page, що є тим $hook_suffix, від якого ви отримуєте значення @return add_submenu_page().

Коротше кажучи, просте рішення - зробити $option_groupвідповідність $option_name. Іншою причиною цієї помилки є невірне значення $pageпараметра для виклику add_settings_section( $id, $title, $callback, $page )або add_settings_field( $id, $title, $callback, $page, $section, $args ).

Підказка: $pageмає відповідати $menu_slugдовідковій функції / додати тематичну сторінку.

Просте виправлення

Використовуючи назву користувацької сторінки (у вашому випадку $this->plugin_slug:) як ідентифікатор розділу, ви зможете вирішити проблему. Однак усі ваші варіанти повинні міститись в одному розділі.

Рішення

Для більш надійного рішення внесіть ці зміни до свого Plugin_Name_Adminкласу:

Додати до конструктора:

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

Додайте ці методи:

// White-lists options on custom pages.
// Workaround for second issue: http://j.mp/Pk3UCF
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 ){
        $whitelist_options[$page] = array();
        foreach( $sections as $section )
            if( !empty( $whitelist_options[$section] ) )
                foreach( $whitelist_options[$section] as $option )
                    $whitelist_options[$page][] = $option;
            }
    return $whitelist_options;
}

// 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]))
            $this->page_sections[$page] = array();
        $this->page_sections[$page][$id] = $id;
    }
}

І зміна add_settings_section()викликів: $this->add_settings_section().


Інші примітки до вашого коду

  • Ваш код форми правильний. Вашу форму потрібно подати на options.php, як на мене вказував @Chris_O, і як зазначено в документації API налаштувань WP .
  • Простір імен має свої переваги, але це може зробити його складнішим налагодження та знизити сумісність вашого коду (потрібно PHP> = 5.3, інші плагіни / теми, які використовують автозавантажувачі тощо). Отже, якщо немає вагомих причин для простору імен файлу, не робіть цього. Ви вже уникаєте називати конфлікти, загортаючи свій код у клас. Зробіть назви своїх класів більш конкретними та введіть validate()зворотні дзвінки в клас як загальнодоступні методи.
  • Порівнюючи цитовану платівку котла з плагіном з вашим кодом, схоже, що ваш код насправді заснований на вилці або старої версії котла. Навіть назви файлів та шляхи різні. Ви можете перенести свій плагін на останню версію, але зауважте, що ця платівка котла може не відповідати вашим потребам. Він використовує одиночні кнопки, які, як правило, не рекомендуються . Бувають випадки, коли однотонний візерунок розумний , але це повинно бути усвідомленим рішенням, а не рішенням Goto.

1
Приємно знати, що в апі є помилка. Я завжди намагаюся переглянути код, який я пишу для помилок, які я можу ввести. Звичайно, це передбачає, що я знаю річ чи дві.
gate_engineer

Для всіх, хто стикається
май

5

Я щойно знайшов цю публікацію, шукаючи ту саму проблему. Рішення набагато простіше, ніж виглядає, тому що документація вводить в оману: в register_setting () першим названим аргументом $option_groupє ваш веб-сторінки, а не розділ, в якому ви хочете відобразити налаштування.

У наведеному вище коді ви повинні використовувати

    // Update Settings
    add_settings_section(
        'maintenance', // section slug
        'Maintenance', // section title
        array( $this, 'maintenance_section' ), // section display callback
        $this->plugin_slug // page slug
    );

    // Check Updates Option
    register_setting( 
        $this->plugin_slug, // page slug, not the section slug
        'plugin-name_check_updates', // setting slug
        'wp_plugin_name\validate_bool' // invalid, should be an array of options, see doc for more info
    );

    add_settings_field(
        'plugin-name_check_updates', // setting slug
        'Should ' . $this->friendly_name . ' Check For Updates?', // setting title
        array( $this, 'check_updates_field' ), //setting display callback
        $this->plugin_slug, // page slug
        'maintenance' // section slug
    );

Це неправильно. Дивіться цей робочий приклад (не мій) - gist.github.com/annalinneajohansson/5290405
Xdg

2

Під час реєстрації сторінки варіантів за допомогою:

add_submenu_page( string $parent_slug, string $page_title, string $menu_title, string $capability, string $menu_slug, callable $function = '' )

І реєстрація налаштувань за допомогою

register_setting( string $option_group, string $option_name );

$option_group має бути таким же, як $menu_slug


1

У мене була така ж помилка, але я отримав її по-іншому:

// no actual code
// this failed
add_settings_field('id','title', /*callback*/ function($arguments) {
    // echo $htmlcode; 
    register_setting('option_group', 'option_name');
}), 'page', 'section');

Я не знаю, чому це сталося, але, здається, це register_settingне повинно бути в зворотному дзвінкуadd_settings_field

// no actual code
// this worked
add_settings_field('id','title', /*callback*/ function($arguments) {echo $htmlcode;}), 'page', 'section');
register_setting('option_group', 'option_name');

Я сподіваюся, що це допомагає


0

Я також стикаюся з цією проблемою вже кілька днів, ця помилка припинилася, коли я додав у коментарях рядок:

// settings_fields($this->plugin_slug);

після цього я переспрямовую на options.php, але поки не можу вирішити проблему setting_fields.


я виправив це з функції перевірки !! ;)
Г.Карлес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.