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.