How to write a WordPress plugin?

What is wordpress plugin? A WordPress plugin is a php file in the directory wp-content\plugins\. Complex plugin may have multiple files and more complex directory structure. It can use a separate folder under  wp-content\plugins\ to store its files.  Interestingly, you do not need to write any code except a comment in the php file to use the plugin.

After you login wordpress dashboard and click the Plugins menu item, $wp_list_table->prepare_items() in wp-admin/plugins.php will call get_plugins()  to read the information of all plugins in the plugin directory wp-content\plugins\ to a global variable $plugins.



get_plugins() reads all php files under wp-content\plugins\ and its subdirectories. It searches for predefined fields in every php file using RegExp. For example, if there is a line “Plugin Name: Test Plugin” in your plugin file testplugindir\testplugin.php, it will set the Name field of the information data structure for plugin “testplugindir\testplugin.php” to “Test Plugin”. Usually you need to put all information fields in one of your plugin files. If it happens that multiple php files in your plugin directory have the same token “Plugin Name:”, those files will be considered as different plugins and have different information data structures of their own. $wp_list_table->display(); will actually shows the plugins in the admin panel.

There are other situations that the plugin files get read. For example, wp-admin\plugins.php will load wp-admin\admin.php, where do_action("load-plugins") will call wp_update_plugins to read the files of  all plugins in wp-content\plugins\ to get the upgrade information for them.


Now your plugin file with only comments seems working well, at least it can be displayed in WordPress dashboard. We will add some codes into the plugin file to make it a real plugin,i.e., a plugin that provides some functions.

You probably notice there are some links(“Activate”, “Edit”, “Delete”) below the plugin title in the previous picture. Clicking “Activate” will activate Test Plugin. Let us check the plugin activation code to see how the “Activate” is done. The activate link is also wp-admin\plugins.php with a query parameter “action=activate”. This time plugins.php call activate_plugin() which loads our plugin file testplugin.php(note that previously, to get plugin information, get_plugins() only read the file content of testplugin.php but not actually loaded it.). In non-silent activation mode, three actions activate_plugin, activate_testplugin.php, activated_plugin will be done. After loading the plugin file,  plugins.php redirects to itself with another set of query parameters,which actually updates the plugin status in the dashboard. Since our plugin has no code in its file, there is no effect about the activation. A real plugin will put function calls such as add_action()add_filter('cron_schedules','testplugin_shedule') (to add cron jobs), register_activation_hook(__FILE__,'testplugin_activation')(to hook testplugin_activation to activate_testplugin.php, which would be executed in non-silent activation mode), add_filter ( 'wp_insert_post_data', 'testplugin_shortcode')(if you define a shortcode for your plugin)  in its file so when activated, will do something useful. Similarly, “Deactivate” link will do some deactivation action(if registered) and finally redirect to plugin.php to update plugin status in wordpress dashboard.

To make the test plugin a little more interesting, we add a line of code to bring up a pop up window in browser.

Plugin Name: Test Plugin
Description: This is a test plugin.

echo "<script> alert('Test Plugin activated!')</script>";

We know that when activated, this line of code will be executed, a pop-up window shows up saying “Test Plugin activated!”, then wordpress dashboard is updated.


There are other scenarios that plugin’s php files get loaded. For example, when you access wp-admin/index.php or /index.php, the following code in wp-settings.php will load all active plugins.

foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
wp_register_plugin_realpath( $plugin );
include_once( $plugin );

Although not all plugins have menu in the admin panel, some do have. How to add menu to the sidebar of WordPress admin panel? You can hook a function to the action “admin_menu” at the load time of the plugin, and call add_menu_page/add_submenu_page to add menu and sub-menu in that function.   “admin_menu” action is done in wp-admin/includes/menu.php(so if you do not login wordpress’ backend, the add_menu code won’t never get run).

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

all submenus are stored in global submenu array:

$submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title );

A hook name is formed using the add_submenu_page parameters $menu_slug and $parent_slug(using $parent_slug to find the plugin name from $admin_page_hooks, the hook name is of the form:pluginname_page_menuslug), and used as the name of an action. The hooked function is used to display the page of the submenu.

$_parent_pages[$menu_slug] records the parent slug of this submenu.

all top-level menus are stored in a global $menu array with a digit as the key. all submenus are stored in global $submenu array with the parent slug as the key. all top-level menu of plugins are registered in $admin_page_hooks with the slug of the top-level menu as the key and the plugin name as the value.

The actual display of  the menus are done in wp-admin/admin-header.php by including wp-admin/menu-header.php calling _wp_menu_output( $menu, $submenu ) . You will see a plugin’s top level menu uses the same url as its first submenu item(in other words, top level menu has no link of its own) , and the url is usually admin.php?page=menuslug  if there is a menu hook or plugin file for this submenu item; otherwise it will use $submenu_items[0][2] as the url. For other submenu items, the url would be $sub_item[2] or admin.php?page=menuhook or sub_item[2]?page=menuhook depending on whether it has a menuhook or plugin file. While wordpress itself uses different php files in wp-admin/ to display different configuration pages, plugins usually use wp-admin/admin.php to display their configuration pages because you do not need to repeat most of the work done by admin.php such as showing the menu bar. How to do that?

add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) will generate a hook name for this menu slug and hook $function to the action named after the hook name. Plugin developer just needs to implement the configuration interface in the $function. The menu slug is also used as the parameter to the url of the menu item(admin.php?page=menuslug ). After user clicks the menu item, admin.php will get the menu slug(as the value of page parameter), use the menu slug to get the hook name, and do the action named after that hook name to show the configuration page. The parameters of add_menu_page is worth researching, which even enables you to add a menu icon or adjust the menu position on the sidebar. To thoroughly understand how  add_menu_page and add_submenu_page works can help you resolve such problems  as plugin menu missing or not showing correctly, and customize/hide specific menu items.

Now it is time to add a menu and create an admin page for our test plugin.

function testplugin_addmenu()
  add_menu_page('Test Plugin', 'Test Plugin', 'manage_options', 'testplugin-settings', 'testplugin_settings', 'none',1);
  add_submenu_page('testplugin-settings', 'Settings', 'Settings','manage_options', 'testplugin-settings', 'testplugin_settings');
  add_submenu_page('testplugin-settings', 'Reports', 'Reports', 'manage_options', 'testplugin-reports', 'testplugin_reports');
add_action('admin_menu', 'testplugin_addmenu');

function testplugin_settings()
<form id="settings" method="post">

<textarea rows="4" cols="50">some settings</textarea><br/>
<input type="submit" name="update" value="Update"/>



function testplugin_reports()


The above code will add an admin menu for our test plugin. The menu has two submenus: Settings and Reports. The following is the Settings admin page.


Cool, isn’t it? But the setting page does not do any work till now. The aim of creating a setting admin page is that user can fill values to some fields then the values are saved in server’s database to be used by our plugin. For example, our plugin need customized options: testplugin_option1, testplugin_option2. The values of the two options are set by users via the setting page. We should group the two options together into a group called testplugin-settings-group, then register the group at admin-init. Specifically,

function register_testpluginsettings()
  register_setting('testplugin-settings-group', 'testplugin_option1');
  register_setting('testplugin-settings-group', 'testplugin_option2');

add_action('admin_init', 'register_testpluginsettings');

The form on our setting page should post to options.php, which will collect the user-provided values and store them to the database. Specifically,

the form should be modified as:

<form id="settings" method="post" action="options.php" >
<?php settings_fields('testplugin-settings-group'); ?>

<input type="text"   name="testplugin-option1" value=""/>

<input type="text"  name="testplugin-option2" value=""/>

<input type="submit"  name="update" value="Update"/>


<?php settings_fields('testplugin-settings-group'); ?>

 will insert several hidden fields to notify options.php that the form is about the settings of the group testplugin-settings-group. options.php will look for the registered group testplugin-settings-group to see what fields are there to be set up, then look for the values from the $_POST[] array named after those fields(in this case, “testplugin-option1″ and “testplugin-option2″), and save them to the database table wp_options. The above is the common wordpress plugin settings page framework. There exist other plugin settings apis for you to collect user configuration parameters for example, on the existed  settings page.

We have created a simple wordpress plugin from scratch and developed admin pages for the plugin to collect user options and save them into the database.  After reading this tutorial, I believe you can make your own wordpress plugin now.

In the next article, we will develop a real plugin that defines a widget to be used on homepage.


Leave a Reply