【翻译】wordpress在后台自定义菜单页面上实现TAB页

之前写过一篇关于给主题增加配置项的东西,那时使用的是add_theme_page()函数。后来WP结构调整,这个函数虽然还能用,但不能跟预览挂钩,已经逐渐淘汰了,取而代之的是customizer的用法。
add_theme_page()有个同胞兄弟,一看就是给插件用的,叫add_plugins_page()。现在的插件一般也不用这个函数了,而是用add_menu_page()函数来增加后台配置页面。
这三个函数其实是一回事,而且也不是这篇文章的重点。

配置项的内容当然可以自己画。但WP已经定义好了一组API来帮你,这些API被称作“WP Settings API”。
WP把一个配置页面划分成Page,Secition和Field。关系见下图(via
20181029-settings-api-page-anatomy
这也不是今天的重点。我要做的是让不同的Section作为不同的Tab页存在。
一切用例子来说话吧。

1)上那个自动生成配置项代码的网站,增加两个测试框,然后点击“Let’s Go”。生成了一堆代码。
20181029-code-gen1
20181029-code-gen2

<?php
add_action( 'admin_menu', 'wp_pcd_add_admin_menu' );
add_action( 'admin_init', 'wp_pcd_settings_init' );


function wp_pcd_add_admin_menu(  ) { 

	add_menu_page( 'plugin_config_demo', 'plugin_config_demo', 'manage_options', 'plugin_config_demo', 'wp_pcd_options_page' );

}


function wp_pcd_settings_init(  ) { 

	register_setting( 'pluginPage', 'wp_pcd_settings' );

	add_settings_section(
		'wp_pcd_pluginPage_section', 
		__( 'Your section description', 'wordpress' ), 
		'wp_pcd_settings_section_callback', 
		'pluginPage'
	);

	add_settings_field( 
		'wp_pcd_text_field_0', 
		__( 'Settings field description', 'wordpress' ), 
		'wp_pcd_text_field_0_render', 
		'pluginPage', 
		'wp_pcd_pluginPage_section' 
	);

	add_settings_field( 
		'wp_pcd_textarea_field_1', 
		__( 'Settings field description', 'wordpress' ), 
		'wp_pcd_textarea_field_1_render', 
		'pluginPage', 
		'wp_pcd_pluginPage_section' 
	);


}


function wp_pcd_text_field_0_render(  ) { 

	$options = get_option( 'wp_pcd_settings' );
	?>
	<input type='text' name='wp_pcd_settings[wp_pcd_text_field_0]' value='<?php echo $options['wp_pcd_text_field_0']; ?>'>
	<?php

}


function wp_pcd_textarea_field_1_render(  ) { 

	$options = get_option( 'wp_pcd_settings' );
	?>
	<textarea cols='40' rows='5' name='wp_pcd_settings[wp_pcd_textarea_field_1]'> 
		<?php echo $options['wp_pcd_textarea_field_1']; ?>
 	</textarea>
	<?php

}


function wp_pcd_settings_section_callback(  ) { 

	echo __( 'This section description', 'wordpress' );

}


function wp_pcd_options_page(  ) { 

	?>
	<form action='options.php' method='post'>

		<h2>plugin_config_demo</h2>

		<?php
		settings_fields( 'pluginPage' );
		do_settings_sections( 'pluginPage' );
		submit_button();
		?>

	</form>
	<?php

}

?>


2)把生成的东西存成一个配置页面,比如option.php,放在插件目录下。
注意,第8行第4个参要改成__FILE__

add_menu_page( 'plugin_config_demo', 'plugin_config_demo', 'manage_options', __FILE__, 'wp_pcd_options_page','' );

3)在插件的主文件里加上下面代码:

if (is_admin())
{
    require_once( plugin_dir_path( __FILE__ ) . '/options.php');
}

至于怎么作个插件,一搜到处都是,要是你不知道的话,那么就请先搜一下之后再往下看,我没有“伪原创”的习惯。
刷新一下后台,这个简陋的页面就出来了,可以看到,两个文本框此时是上下排列的。
20181029-before

4)在主描绘函数wp_pcd_options_page()里加点料。
4.1)增加当前tab页的选择信息

if( isset( $_GET[ 'tab' ] ) ) {
        $active_tab = $_GET[ 'tab' ];
    } else {
        $active_tab = 'tab_1';
    }

4.2)增加两个tab页的链接。链接加在form前面。
tab的风格用”nav-tab-wrapper”和”nav-tab-active”的话,WP的默认风格会帮我们搞定一切。

<h2 class="nav-tab-wrapper">
    <a href="?page=<?php echo __FILE__;?>&tab=tab_1" class="nav-tab <?php echo $active_tab == 'tab_1' ? 'nav-tab-active' : ''; ?>">Tab One</a>
    <a href="?page=<?php echo __FILE__;?>&tab=tab_2" class="nav-tab <?php echo $active_tab == 'tab_2' ? 'nav-tab-active' : ''; ?>">Tab Two</a>
</h2>

4.3)把form里的东西也分开。
4.3.1)我们把原来的settings_fields()、do_settings_sections()拆成两部分。
当然这是以两个tab为例子,如果更多就多加else好了。

  if( $active_tab == 'tab_1' ) {
      settings_fields( 'pluginPage' );
      do_settings_sections( 'pluginPage' );
  }
  else {
      settings_fields( 'pluginPage666' );
      do_settings_sections( 'pluginPage666' );
  }

4.3.2)当然要补上叫666的坑。
在wp_pcd_settings_init()里,追加一个section。还记得前面那张图吗?

add_settings_section(
		'wp_pcd_pluginPage_section666',//section名
		__( '新追加的section', 'wordpress' ),//描述
		'wp_pcd_settings_section666_callback',//回调函数,其实可以留空
		'pluginPage666'//group名。必须与settings_fields()、do_settings_sections()里一致
	);

再把已经存在的第二个文本框“挪”到第二个tab页里。主要是修改后面两个参数。

	add_settings_field(
		'wp_pcd_textarea_field_1',
		__( '第二页', 'wordpress' ),
		'wp_pcd_textarea_field_1_render',
		'pluginPage666',
		'wp_pcd_pluginPage_section666'
	);

然后还有一个callback要写。

function wp_pcd_settings_section666_callback(  ) {

	echo '选中了第二个tab页';

}

看,样子变了吧,点击tab页试试吧。
20181029-after1
20181029-after2

下面是最终代码。跟原始代码比较是理解追加和修改的过程的最好办法。希望对您的开发有所帮助。

<?php
add_action( 'admin_menu', 'wp_pcd_add_admin_menu' );
add_action( 'admin_init', 'wp_pcd_settings_init' );


function wp_pcd_add_admin_menu(  ) {

	add_menu_page( 'plugin_config_demo', 'plugin_config_demo', 'manage_options', __FILE__, 'wp_pcd_options_page','' );

}


function wp_pcd_settings_init(  ) {

	register_setting( 'pluginPage', 'wp_pcd_settings' );

	add_settings_section(
		'wp_pcd_pluginPage_section',
		__( 'Your section description', 'wordpress' ),
		'wp_pcd_settings_section_callback',
		'pluginPage'
	);

    add_settings_section(
		'wp_pcd_pluginPage_section666',
		__( '新追加的section', 'wordpress' ),
		'wp_pcd_settings_section666_callback',
		'pluginPage666'
	);

	add_settings_field(
		'wp_pcd_text_field_0',
		__( 'Settings field description', 'wordpress' ),
		'wp_pcd_text_field_0_render',
		'pluginPage',
		'wp_pcd_pluginPage_section'
	);

	add_settings_field(
		'wp_pcd_textarea_field_1',
		__( '第二页', 'wordpress' ),
		'wp_pcd_textarea_field_1_render',
		'pluginPage666',
		'wp_pcd_pluginPage_section666'
	);


}


function wp_pcd_text_field_0_render(  ) {

	$options = get_option( 'wp_pcd_settings' );
	?>
	<input type='text' name='wp_pcd_settings[wp_pcd_text_field_0]' value='<?php echo $options['wp_pcd_text_field_0']; ?>'>
	<?php

}


function wp_pcd_textarea_field_1_render(  ) {

	$options = get_option( 'wp_pcd_settings' );
	?>
	<textarea cols='40' rows='5' name='wp_pcd_settings[wp_pcd_textarea_field_1]'>
		<?php echo $options['wp_pcd_textarea_field_1']; ?>
 	</textarea>
	<?php

}


function wp_pcd_settings_section_callback(  ) {

	echo __( 'This section description', 'wordpress' );

}

function wp_pcd_settings_section666_callback(  ) {

	echo '选中了第二个tab页';

}



function wp_pcd_options_page(  ) {
    if( isset( $_GET[ 'tab' ] ) ) {
        $active_tab = $_GET[ 'tab' ];
    } else {
        $active_tab = 'tab_1';
    }
	?>
    <h2 class="nav-tab-wrapper">
        <a href="?page=<?php echo __FILE__;?>&tab=tab_1" class="nav-tab <?php echo $active_tab == 'tab_1' ? 'nav-tab-active' : ''; ?>">Tab One</a>
        <a href="?page=<?php echo __FILE__;?>&tab=tab_2" class="nav-tab <?php echo $active_tab == 'tab_2' ? 'nav-tab-active' : ''; ?>">Tab Tow</a>
    </h2>
	<form action='options.php' method='post'>

		<h2>plugin_config_demo</h2>

		<?php
        if( $active_tab == 'tab_1' ) {
      settings_fields( 'pluginPage' );
      do_settings_sections( 'pluginPage' );
  }
  else {
      settings_fields( 'pluginPage666' );
      do_settings_sections( 'pluginPage666' );
  }
		submit_button();
		?>

	</form>
	<?php

}

?>

P.S:原文是一段代码,前面都是我自己的理解。我觉得翻译代码也是一种翻译。
via

已有5条评论

  1. 因为 WordPress 的代码实在太肿了,而且插件仓库还不是 git 管理,所以一直没研究过这些玩意,自制的插件也都是免配置的。

    1. 确实有很多东西应该甩出去。但我真的很喜欢wordpress的钩子机制。

      1. 钩子机制可以说是 WordPress 的精华了,只不过几年前的大更新后,官方文档就有点脱节,想介入开发变得很困难。

        1. 我被绑在wp这个破车上13年了,换是没法换的了。

          1. 有没有新能源车,简单高效一点,基本功能齐全。

          2. 不了解唉。我是信奉篱笆不破就不要去补的那类人。

          3. 我上车也有10年了,现在还是用的 4.3,每次出新版都自己手工 merge 代码。
            我要是换我就干脆自己写了,毕竟主修的就是 PHP ,写博客自用的话没难度,只不过做不出来钩子,扩展都得改代码了。
            没换的必要,就个人写个文章,哪来那么多新需求。当时升 4.4 第一版出一堆 Bug 我直接就回退了,之后一直没升过大版本。

          4. 4.0的时候,主要功能是主题的预览,以及一堆媒体的东西。当时就觉得没什么大用了。那时后台设置是不升级,但当时用的虚拟主机,服务商后来偷摸给自动升了,让我好一阵恼火,也坚定了我换VPS的决心。
            功能上不觉得WP能有什么进步了。现在5.0听说主要是加古腾堡,没什么卵用。但是吧,每次要是它说有安全方面的更新又不敢不管。没那个精力像你那样比较代码,再说php我也仅限于对着手册和代码能用,完全说不上精通。
            4.4是不是后台中文包少了半个括号导致打开白屏那次?我后台从来不设成中文,感觉完全没必要。

  2. 按的wordpress刚起步,不小心跑到这里,发现你的后台居然是纯英文的,牛气了啊,插件制作我是学不会了。

    1. 这是个历史遗留问题。主要是我刚开始用wordpress那会儿,还没有语言包这个东西,早习惯了。

你好,新朋友。留言前请先填写昵称邮箱