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:
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 deadd_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 appelezadd_settings_section( $id, $title, $callback, $page )
ouadd_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.
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.
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()
.
validate()
dans la classe en tant que méthodes publiques.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
);
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
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
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
.