The WordPress Settings API (docs) is used to create settings pages and save settings in the options table. But I didn’t need a setting, I needed a settings page to create/update a post.
Of course I could have created my own custom settings page and not use the settings API. But the settings API does have a couple of advantages.
- Nonces validation.
- Still using a WordPress standard.
- Saving and error notices by default and customizable.
- Mix with regular options.
First off create a settings page like we are used to:
<?php
add_action( 'admin_menu', 'register_menu_item' );
function register_menu_item() {
add_submenu_page(
'options-general.php',
__( 'Settings page title' ),
__( 'Menu title' ),
'manage_options',
'page-slug',
function () {
require './templates/settings-page.php';
}
);
}
add_action( 'admin_init', 'register_settings' );
/**
* Register settings to save.
*/
function register_settings() {
register_setting(
'fake-option',
'fake-option',
array( 'sanitize_callback' => 'save_post' )
);
}
/**
* This function will only be called when the "option" is valid to save.
* Here we validate our own fields and create the post we want.
*
* @param null|array $unused_fake_setting
*/
function save_post( $unused_fake_setting ) {
// Nonces are validated before we get here.
static $first_run = true; // this function can be called twice, but we only need it once.
if ( ! $first_run ) {
return;
}
$first_run = false; // Never run again, this request.
if ( empty( $_POST['log_title'] ) ) {
add_settings_error( 'fake-option', 'title-empty', __( "Log title can't be empty." ) );
return;
}
$title = wp_unslash( $_POST['log_title'] );
$title = sanitize_text_field( $title );
// validate other fields...
// save the post.
wp_insert_post( array(
'post_title' => $title
// add other attributes.
) );
// success message, yes the function name is confusing.
add_settings_error( 'wpjm-ch-save', 'term-added', __( 'Worker successfully connected', 'success' ) );
}
And the templates/settings-page.php
file:
<div class="wrap">
<h1><?php esc_html_e( 'Settings page title' ); ?></h1>
<form action="options.php" method="POST">
<?php settings_fields( 'fake-option' ); ?>
<h2><?php esc_html_e( 'Add log' ); ?></h2>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row"><label for="log_title"><?php esc_html_e( 'Log title' ); ?></label></th>
<td><input name="log_title" id="log_title" type="url" class="regular-text" required/></td>
</tr>
<tr>
<th scope="row">More fields</th>
<td></td>
</tr>
</tbody>
</table>
<?php submit_button( __( 'Add log' ) ); ?>
</form>
</div>
How it works
We basically add settings like normal, except we skip a few things
First off normally you would add a section using add_settings_section in the same function where we register the settings field(s). But as we don’t really render a settings field in the template, we don’t add it at all. The same goes for the do_settings_sections in the Template.
In the settings template we do have the regular settings_fields this makes sure all the nonce fields are printed. And the submit_button.
Finally the thing we do extra and where the magic happens.
In the sanitize_callback
of the register_setting function we set the save_post
function.
Normally this is for sanitizing the option you want to save. But in this case we are not saving a option, we are saving a post. In this function we validate all the data send by the form, sanitize the data and save a new post.
And when the data is validated and saved we send a success notice with the add_settings_error function. Yes, we send a success notice with the **_error
function. It can be done with the final argument, by setting the type to ‘success’.
Handling multiple custom options.
In the project that sparked this post I need to create a post, but also list those posts with a delete button.
What I found useful was creating a second register_setting
, put them in two separate <form>
tags on the template and let one handle the creating and the other the deleting.
<?php
function register_settings() {
register_setting(
'fake-option-create',
'fake-option-create',
array( 'sanitize_callback' => 'save_post' )
);
register_setting(
'fake-option-delete',
'fake-option-delete',
array( 'sanitize_callback' => 'delete_post' )
);
}
function save_post() {
// handles saveing/creating.
}
function delete_post() {
// handles deleting.
}
?>
<div class="wrap">
<h1><?php esc_html_e( 'Settings page title' ); ?></h1>
<form action="options.php" method="POST">
<?php settings_fields( 'fake-option-create' ); ?>
HTML FORM HERE
<?php submit_button( __( 'Add log' ) ); ?>
</form>
<form action="options.php" method="POST">
<?php settings_fields( 'fake-option-delete' ); ?>
LIST POSTS HERE WITH CHECKBOXES
<?php submit_button( __( 'Delete logs' ) ); ?>
</form>
</div>
Other tweaks.
?php_version=7.4&platform=wordpress&platform_version=5.6&software=free&software_version=15.6.2&days_active=30plus&user_language=en_US
- Create, delete and updates posts (and post meta)
- The same for user(meta and tax(meta)
- External API calls.
- Mix in regular use of the settings API.
- World peace.