web-dev-qa-db-fra.com

"Erreur: page d'options introuvable" dans la soumission de page de paramètres pour un OOP Brancher

Je développe actuellement un plug-in utilisant Boilerplate repository de Tom McFarlin comme modèle, qui utilise les pratiques OOP. J'ai essayé de comprendre exactement pourquoi je suis incapable de soumettre correctement mes paramètres. J'ai essayé de définir l'attribut d'action sur une chaîne vide, comme suggéré dans une autre question ici, mais cela n'a pas aidé ...

Vous trouverez ci-dessous la configuration générale du code que j'utilise ...

Le formulaire (/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>

Pour le code suivant, supposons que tous les rappels pour add_settings_field () et add_settings_section () existent, à l'exception de 'option_list_selection'.

La classe d'admin du plugin (/ {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
        );
    }
}

Quelques mises à jour demandées:

Changer l'attribut d'action pour:

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

... résulte simplement en une erreur 404. Ce qui suit est l'extrait des journaux Apache. Notez que les scripts WordPress et les en-files d'attente CSS par défaut sont supprimés:

# 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

Le fichier php-errors.log et le fichier debug.log lorsque WP_DEBUG a la valeur true sont vides.

La classe de plugin (/{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;

    }

}

Références:

17
gate_engineer

"Erreur: page Options introuvable" bogue

Il s'agit d'un problème connu dans l'API WP Settings. Il y avait un ticket ouvert il y a des années et il était marqué comme résolu - mais le bogue persiste dans les dernières versions de WordPress. Voici ce que la page du Codex (maintenant supprimée) disait à propos de ceci :

La "Erreur: page d'options introuvable." problème (y compris une solution et une explication):

Le problème est alors que le filtre 'whitelist_options' n'a pas le bon index pour vos données. Il est appliqué sur options.php # 98 (WP 3.4).

register_settings() ajoute vos données au $new_whitelist_options global. Ceci est ensuite fusionné avec le $whitelist_options global dans le (s) rappel (s) option_update_filter() (resp. add_option_whitelist()). Ces rappels ajoutent vos données au $new_whitelist_options global avec le $option_group comme index. Lorsque vous rencontrez "Erreur: page d'options introuvable." cela signifie que votre index n'a pas été reconnu. Ce qui est trompeur, c'est que le premier argument est utilisé comme index et nommé $options_group, lorsque la vérification dans options.php # 112 se produit par rapport à $options_page, qui est le $hook_suffix, que vous obtenez comme valeur @return à partir de add_submenu_page().

En bref, une solution simple consiste à faire correspondre $option_group à $option_name. Une autre cause de cette erreur réside dans le fait que le paramètre $page contient une valeur non valide lorsque vous appelez add_settings_section( $id, $title, $callback, $page ) ou add_settings_field( $id, $title, $callback, $page, $section, $args ).

Astuce: $page doit correspondre à $menu_slug de la page de référence de la fonction/ajouter un thème.

Simple Fix

Utiliser le nom de page personnalisé (dans votre cas: $this->plugin_slug) comme identifiant de votre section permettrait de contourner le problème. Cependant, toutes vos options devraient être contenues dans une seule section.

Solution

Pour une solution plus robuste, apportez les modifications suivantes à votre classe Plugin_Name_Admin:

Ajouter au constructeur:

// 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 );

Ajoutez ces méthodes:

// 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;
    }
}

Et changez les appels add_settings_section() en: $this->add_settings_section().


Autres notes sur votre code

  • Votre code de formulaire est correct. Votre formulaire doit être soumis à options.php, comme me l’a souligné @Chris_O et comme indiqué dans la WP API de paramètres documentation .
  • L'espacement de nommage a ses avantages, mais il peut rendre le débogage plus complexe et réduit la compatibilité de votre code (nécessite PHP> = 5.3, d'autres plugins/thèmes qui utilisent des autochargeurs, etc.). Donc, s'il n'y a pas de bonne raison de créer un espace de noms pour votre fichier, ne le faites pas. Vous évitez déjà les conflits de noms en encapsulant votre code dans une classe. Rendez les noms de classe plus spécifiques et introduisez vos rappels validate() dans la classe en tant que méthodes publiques.
  • Si vous comparez votre plugin avec un code , il semble que votre code soit basé sur une fourchette ou sur une ancienne version du maréchal. Même les noms de fichiers et les chemins sont différents. Vous pouvez migrer votre plugin vers la dernière version, mais sachez que ce plugin boilerplate n'est peut-être pas adapté à vos besoins. Il utilise des singletons généralement découragés . Il y a des cas où le motif singleton est sensible , mais cela doit être une décision consciente, pas la solution goto.
20

Je viens de trouver ce post en cherchant le même problème. La solution est beaucoup plus simple qu'il n'y paraît, car la documentation est trompeuse: dans register_setting () , le premier argument nommé $option_group est votre slug de page, pas la section dans laquelle vous souhaitez afficher le paramètre.

Dans le code ci-dessus, vous devriez utiliser

    // 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
    );
3
86Dev

Lors de l’enregistrement de la page d’options avec:

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

Et enregistrer les paramètres avec

register_setting( string $option_group, string $option_name );

$option_group devrait être identique à $menu_slug

2
Cafer Elgin

J'ai eu la même erreur mais je l'ai eu d'une manière différente:

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

Je ne sais pas pourquoi c'est arrivé, mais il semble que register_setting ne devrait pas figurer dans le rappel de 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');

J'espère que ça aide

0
A new 1

Cela fait aussi quelques jours que je suis confronté à ce problème, cette erreur s’est arrêtée lorsque j’ai mis en commentaire la ligne suivante:

// settings_fields($this->plugin_slug);

après cela, je redirige vers options.php mais je ne peux pas encore résoudre le problème de setting_fields.

0
G.Karles