«Erreur: page d'options introuvable» dans la soumission de page de paramètres pour un plug-in POO

12

Je suis en train de développer un plugin en utilisant le référentiel Boilerplate de Tom McFarlin , qui utilise les pratiques de la POO. 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, sauf pour 'option_list_selection'.

Classe d'administration de plug-in (/ {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
        );
    }
}

Certaines mises à jour demandées:

Modification de l'attribut d'action en:

<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 plug-in (/{plugin-nameBuch-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:

posée gate_engineer 30.03.2014 - 07:36

3 réponses

15

Bogue "Erreur: page d'options introuvable"

Il s'agit d'un problème connu dans l'API de paramètres WP. Un ticket a été ouvert il y a plusieurs années. Il était marqué comme étant résolu, mais le bogue persiste dans les dernières versions. de WordPress. C’est ce que a été supprimé de la page du Codex à ce sujet :

  

La "Erreur: page d'options introuvable." problème (y compris une solution et   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   global $new_whitelist_options . Ceci est alors fusionné avec le global    $whitelist_options dans le option_update_filter() (resp.    add_option_whitelist() ) rappel (s). Ces rappels ajoutent vos données au global $new_whitelist_options avec le $option_group en tant qu'index.   Lorsque vous rencontrez "Erreur: page d'options introuvable." cela signifie que votre   L'index n'a pas été reconnu. La chose trompeuse est que le premier   L'argument est utilisé comme index et est nommé $options_group , lorsque la vérification réelle dans options.php # 112 se produit contre $options_page , qui correspond au $hook_suffix , que vous obtenez en tant que valeur @return de add_submenu_page() .

     

En bref, une solution simple consiste à faire en sorte que $option_group corresponde à $option_name . Une autre cause de cette erreur est d'avoir une valeur non valide pour le paramètre $page lors de l'appel de add_settings_section( $id, $title, $callback, $page ) ou add_settings_field( $id, $title, $callback, $page, $section, $args ) .

     

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

Solution simple

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

Solution

Pour une solution plus robuste, apportez ces modifications à votre Plugin_Name_Admin class:

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 remplacez add_settings_section() les appels par: $this->add_settings_section() .

Autres notes sur votre code

  • Votre code de formulaire est correct. Votre formulaire doit être soumis à options.php, comme l’a indiqué @Chris_O et l’API de paramètres WP dans la documentation .
  • L’espacement de noms présente des avantages, mais il peut rendre le débogage plus complexe et réduit la compatibilité de votre code (requiert PHP > = 5.3, d’autres plugins / thèmes utilisant des autochargeurs, etc.). Donc, s'il n'y a pas de bonne raison de créer un espace de noms pour votre fichier, non. Vous évitez déjà les conflits de noms en encapsulant votre code dans une classe. Spécifiez les noms de classe plus en détail et introduisez vos callbacks validate() dans la classe en tant que méthodes publiques.
  • Si vous comparez votre plug-in warmplate cité avec votre code, il semble que votre code soit réellement basé sur une fourchette ou une ancienne version du passe-partout. 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 peut ne pas convenir à vos besoins. Il utilise des singletons, qui sont généralement découragés . Il existe des cas où le modèle de singleton est sensible , mais cette décision doit être prise de manière consciente et non pas la solution de suivi. .
réponse donnée Stephen M. Harris 02.04.2014 - 21:45
1

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
    );
    
réponse donnée 86Dev 27.10.2017 - 01:37
0

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

    
réponse donnée Cafer Elgin 06.10.2018 - 20:49

Lire d'autres questions sur les étiquettes