我正在开发一个插件,使用Tom McFarlin\'s Boilerplate 存储库作为模板,它利用OOP实践。我一直在试图弄清楚为什么我无法正确提交设置。我已经尝试将action属性设置为一个空字符串,正如这里的另一个问题所建议的那样,但这没有帮助。。。
下面是我正在使用的常规代码设置。。。
The Form (/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>
对于下面的代码,假设除了“option\\u list\\u selection”之外,add\\u settings\\u field()和add\\u settings\\u section()的所有回调都存在。
The Plugin Admin Class(/{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
);
}
}
Some Requested Updates:
将操作属性更改为:
<form action="../../options.php" method="post">
。。。只会导致404错误。下面是Apache日志的摘录。请注意,默认WordPress脚本和CSS en队列已删除:
# 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错误。日志文件和调试。WP\\u DEBUG为true时的日志文件为空。
The Plugin Class (/{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;
}
}
References:
最合适的回答,由SO网友:Stephen M. Harris 整理而成
“错误:找不到选项页。”问题(包括解决方案和解释):
问题是,“whitelist\\u options”过滤器没有为您的数据建立正确的索引。它应用于选项。php#98(WP 3.4)。
register_settings()
将数据添加到全局$new_whitelist_options
. 然后将其与全局$whitelist_options
内部option_update_filter()
(分别为。add_option_whitelist()
) 回调。这些回调将您的数据添加到全局$new_whitelist_options
使用$option_group
作为索引。当您遇到“错误:找不到选项页”这意味着您的索引尚未被识别。令人误解的是,第一个参数被用作索引并命名为$options_group
, 当实际签入选项时。php#112发生在$options_page
, 哪个是$hook_suffix
, 您从中获得@返回值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
) 因为你的部门id可以绕过这个问题。但是,您的所有选项都必须包含在单个部分中。
解决方案要获得更强健的解决方案,请对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()
.
代码上的其他注释您的表单代码是正确的。您的表单必须提交到选项。php,正如@Chris\\u O向我指出的,以及WP设置API中指出的documentation.名称空间有它的优点,但它会使调试更加复杂,并降低代码的兼容性(需要PHP>=5.3、其他使用自动加载程序的插件/主题等)。因此,如果没有很好的理由对文件命名,就不要这样做。通过将代码包装到类中,已经可以避免命名冲突。使您的类名更加具体,并validate()
作为公共方法回调到类中比较你引用的plugin boilerplate 对于您的代码,看起来您的代码实际上是基于fork或旧版本的样板文件。甚至文件名和路径也不同。您可以将插件迁移到最新版本,但请注意,此插件样板文件可能不适合您的需要。它使用单例,通常discouraged. 有些情况下,单例模式是sensible, 但这应该是有意识的决定,而不是goto解决方案