
The specific properties of the post, made to the structure of the site by your plugin, are configured using metaboxes. These are panels containing all the necessary configuration items. They are located on the editing screens.
Metabox cannot do when new properties
* involved in most posts;
* have strict limitations (for example, the number of a specific format);
* it is difficult or inconvenient to enter as strings (for example, values ​​from the list);
* interconnected with each other and are one.
If the properties can be displayed as a string, they affect a small number of posts and do not have strict restrictions on the format - for them you can use the “Custom fields” metabox on the post editing page.
Stocking
For experimentation purposes, we will create a simple plugin. It will consist of one script. Let's call it metatest.php and put it directly in wp-content.
')
Here is the minimum required for the metabox to appear on the record editing page after the plug-in is activated:
<?php add_action('add_meta_boxes', 'metatest_init'); function metatest_init() { add_meta_box('metatest', 'MetaTest- ', 'metatest_showup', 'post', 'side', 'default'); } function metatest_showup() { echo '<p> </p>'; } ?>
When you create your own metaboxes, the add_meta_boxes hook is activated. We tied to it the metatest_init function, which creates the box 'MetaTest-parameters of the post' in the sidebar of the post editing screen. Its content is formed by the metatest_showup function. The result is located between the “Record Miniature” and “Tags” boxes:

All the work here is done by the add_meta_box function. Its definition looks like this:
function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null) ...
Appearance and content are given by the first three arguments: $ id - the metabox identifier, $ title - the title, $ callback - the function that produces the contents of the metabox.
When forming the screen, the identifier $ id is given to the section containing the metabox. The identifier of the checkmark that defines the display of the box and is located in the settings of the screen is formed as "{$ id} -hide".

This can be useful when setting styles or when used in scripts.
All other arguments are optional.
The following three of them define the location: $ screen - the screen for editing a post of a particular type, $ context - the position on this screen, $ priority - the priority for the boxes located on the same screen and in the same context.
The value of the $ screen argument is, in fact, the type of posts whose edit page is meant. Of the standard WordPress owns initially, this is 'post' (post), 'page' (page) and 'attachment' (media files and other attachments). If the value is not set (or is null equal), the metabox will be present on all screens, regardless of the type of post being edited.
The position specified in $ context can be one of the following: 'normal' - the main editing elements - the upper part of the central column; 'advanced' - additional elements - the lower part of the central column; 'side' - sidebar, the screen should have two columns. After a manual change, WordPress remembers the position of the metabox and ignores the defaults set in add_meta_box. Therefore, to familiarize with the placement, you can add three more of the same box in different contexts:
foreach (array('normal', 'advanced', 'side') as $context) add_meta_box('metatest_' . $context, 'MetaTest ' . $context, 'metatest_meta_box_showup', 'post', $context, 'default');
Argument $ priority sets the priority for placing the panel in relation to the rest. The higher the priority, the earlier the panel will be rendered. Possible priority values, in descending order: 'high', 'core', 'default', 'low'.
An arbitrary parameter is passed to $ callback_args for the $ callback function. It takes two arguments: an editable post (an instance of the WP_Post class) and information about the metabox. The information is contained in an array, the keys of which are almost the same with the arguments add_meta_box: 'id', 'title', 'callback' and 'args'. The value of $ callback_args is placed in 'args':
function showup_fn($post, $box) { $args = $box['args']; ... }
You can pass multiple arguments as an array
array('var0' => $var0, 'var1' => $var1, ...)
Inside the expression function
extract($box['args']);
put $ varN variables in the current scope.
Metadata
One of the main tasks of the metabox is editing post-related data. The Arbitrary Fields panel performs the same task, but the fields whose names begin with the underscore character are ignored by it. This should be remembered to protect data from uncontrolled changes.
The formation of input fields and the output of existing values ​​(or default values) are assigned to the metabox drawing function. Information is retrieved from the database and placed in the input field:
function metatest_showup($post, $box) {
At the moment, the necessary metadata is not contained in the database, and the input field will be empty. Filling it yet will not do anything. Saving is not implemented and WordPress does not respond to the field.
Save function
Edited information comes from the user by clicking on the button “Save” or “Publish / Update”. Upon receiving it, WordPress activates the 'save_post' hook. To it should bind a function that checks and writes metadata to the database:
add_action('save_post', 'metatest_save'); function metatest_save($postID) { ... }
The first (and, in this case, the only) function argument is the identifier of the saved post. The saved post itself can be obtained either by calling get_post ($ postID), or by the second argument:
function metatest_save($postID, $post) ...
In this case, the number of arguments to be taken should be explicitly specified in the fourth parameter, add_action:
add_action('save_post', 'metatest_save', 10, 2);
The penultimate parameter — the priority of the execution of our function — takes its default value (from wp-includes / plugin.php).
The 'save_post' action is performed with two arguments: the post ID and the post itself as an instance of the WP_Post class. Therefore, there is no sense in more arguments.
The metatest_save function is a bit more complicated than the rest in our plugin. Her plan looks like this:
* we check availability of information from our metabox;
* check accepting her post;
* we are convinced of the authenticity of its source;
* we control the correctness of the data and eliminate potentially dangerous sequences;
* Finally, we keep clean information in the database.
Checks
All user submitted information is in the $ _POST global array. But the fields of our metadata in it for various reasons may not be: when autosaving, saving a post of a different type, when creating empty posts during the formation of an editing screen, etc. The test for its presence is quite simple:
if (!isset($_POST['metadata_field'])) return;
If there is no field, we exit.
A couple of significant moments are associated with the target post.
The first moment - revisions. Each new revision of a post supersedes its previous contents into a revision — a child, unchangeable post. At the same time, another 'save_post' is activated, already with the revision identifier. Thus, the metatest_save function will be called twice, and the only difference in calls is the value of $ postID.
The owner of the metadata is the post. Therefore, saving revisions should be ignored:
if (wp_is_post_revision($postID)) return;
The wp_is_post_revision function returns true if the identifier passed in the argument belongs to a revision.
The second point is autosave. Occurs regularly when editing a post, by default - every two minutes. This information is sent incomplete - only that with regard to the text of the post. Usually, in this case, there is enough checking for the presence of data in $ _POST. But since in future versions (from 3.6), metadata is promised to belong to revisions, and since the behavior of WordPress is highly dependent on plug-ins, you should not ignore the auto-save check.
Autosave created for the post - type of audit. In response to its identifier, the wp_is_post_revision function will also return true. But there is a pitfall: when autosaving drafts, the 'save_post' hook is activated with the post ID, and this function will not work.
The same can be said about the specialized wp_is_post_autosave: it will work only when auto-saving an already published post:
if (wp_is_post_autosave($postID)) {
In this case, one should rely on the DOING_AUTOSAVE constant, which is set to true by the wp_ajax_autosave function, which is called by the server when receiving autosave data. (The wp_ajax_autosave function is located in wp-admin / includes / ajax-actions.php). Corresponding code may look like this:
if (exists('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
Autosave in progress can also be determined by the value of $ _POST ['action'] == 'autosave'.
Source authentication is based on a one-time code embedded in the form to our input fields. It helps to protect the site from attacks like CSRF. In such attacks, the browser of an authorized user, by executing the code of the attacker, performs actions with the authority of this user. In this case, it sets the eigenvalues ​​of our metadata.
The installation must be placed in the formation code of the metabox body:
wp_nonce_field("metatest_action", "metatest_nonce"); : check_admin_referer("metatest_action", "metatest_nonce");
Correctness control
Now, when we work with the target post, we have the necessary fields and are confident in the reliability of their source, we can proceed to their processing.
First of all, you should check the correctness of the stored metadata. Two conditions must be met:
1) data is acceptable;
2) the data is safe;
The acceptance criterion completely depends on the problem to be solved - the allowable values ​​for enumerations, the absence of obscene language in the text, etc.
The update_post_meta function will take care of the security of the metadata regarding the database.
In relation to the site and users, data security is determined by the methods of their application. There should not be uncontrolled HTML, interpreted arbitrary javascript, loopholes for malicious URLs, etc.
In our case, the metadata is a string. Therefore, it makes sense to save it from unnecessary spaces, hyphenations and incorrect unicode characters. For these purposes, the sanitize_text_field function serves to return the adjusted version of the argument string:
$string = sanitize_text_field($string);
Preservation
Data recording - the purpose of the function - is made in one call
update_post_meta($postID, '_metatest_data', $string);
Notice the underscore character that starts the field name. It makes the field inaccessible from the "arbitrary fields" panel.
Total
Now we apply all the theory in practice. The title of the plugin looks the same, only the registration of the save function is added:
<?php
The metabox drawing function has been replenished with the formation of a one-time code and now looks like this:
function metatest_showup($post, $box) {
But the function of saving data:
function metatest_save($postID) {
The result, after saving the string “Hello, world!” And refreshing the page, should look like this:

As you can see, the simplest metabox is easy to create. It relies on two hooks, 'add_meta_box' and 'save_post', and consists of two functions — outputting the form body and saving data.
But this is only the starting point. In real cases, there are more fields, the forms are more complicated, and the data is related both to each other and to the functionality of the plug-in and the components of the theme. Therefore, neither the complexity of the tasks being solved, nor the stuffing of metaboxes, is unlimited.