Last active
March 11, 2017 11:09
-
-
Save zacscott/79a27afead4f12cd0a83 to your computer and use it in GitHub Desktop.
Settings builder utility for WordPress (can be used as a mu-plugin)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
add_action( 'plugins_loaded', function() { | |
$settings = new zacscott\SettingsBuilder(); | |
$settings->page( array( | |
'title' => 'TEST ', | |
'menu' => 'Test Settings', | |
) ); | |
$settings->section( array( | |
'title' => 'Test Settings', | |
) ); | |
$settings->text( array( | |
'label' => __( 'Textual option', 'text_domain' ), | |
'option' => 'text_op', | |
) ); | |
$settings->number( array( | |
'label' => __( 'Number option', 'text_domain' ), | |
'option' => 'number_op', | |
) ); | |
$settings->bool( array( | |
'label' => __( 'Boolean option', 'text_domain' ), | |
'option' => 'bool_op', | |
) ); | |
$settings->select( array( | |
'label' => __( 'Select options', 'text_domain' ), | |
'option' => 'select_op', | |
'vals' => array( | |
'test1' => 'Test 1', | |
'test2' => 'Test 2', | |
'test3' => 'Test 3', | |
) | |
) ); | |
$settings->build(); | |
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Plugin Name: Settings Builder | |
* Description: Simple WP settings builder API | |
* Version: 1.0 | |
* Author: Zachary Scott | |
*/ | |
namespace zacscott; | |
/** | |
* A single settings field in a Section. Used internally by Section. | |
* | |
* @author Zachary Scott <zscott.dev@gmail.com> | |
*/ | |
class Field { | |
public $args = array(); | |
public function __construct( $args ) { | |
assert( ! empty( $args ) ); | |
$this->args = $args; | |
} | |
/** | |
* Registers the settings field with WordPress. | |
* Must be called within 'admin_init' hook. | |
* | |
* @param $id The ID of the setting field. | |
* @param $page The Page object which this field belongs to. | |
*/ | |
public function build( $id, $page ) { | |
assert( ! empty( $id ) ); | |
assert( ! empty( $page ) ); | |
if ( 'hr' !== (string) $this->type ) { // dont register setting for <hr> | |
// register the option setting | |
register_setting( | |
$page, | |
$this->option, | |
array( $this, 'validate' ) | |
); | |
} | |
add_settings_field( | |
$this->option, | |
$this->label, | |
array( $this, $this->type ), | |
$page, | |
$id, | |
array( // args to callback | |
$this->vals | |
) | |
); | |
} | |
// Validates the setting field. | |
function validate( $value ) { | |
$validate = $this->validate; | |
if ( ! empty( $validate ) ) { | |
$err = call_user_func( $validate, $value ); | |
// report error - if any | |
if ( ! empty( $err ) ) { | |
add_settings_error( $this->option, $this->option, $err ); | |
return get_option( $this->option ); // failed - revert to previous value | |
} | |
} | |
return $value; | |
} | |
// Output <input type="checkbox"/> | |
function bool() { | |
assert( 'bool' === (string) $this->type ); | |
$val = get_option( $this->option ); | |
$name = $this->option; | |
echo "<label for='". esc_attr( $name ) ."'>"; | |
echo "<input type='checkbox' id='". esc_attr( $name ) ."' name='". esc_attr( $name ) ."' "; | |
echo esc_attr( $val ? "checked='checked'" : '' ); | |
echo "/> \n"; | |
echo esc_html( $this->placeholder ); | |
echo '</label>'; | |
} | |
// Output <input type="text"/> | |
function text() { | |
assert( 'text' === (string) $this->type ); | |
$val = get_option( $this->option ); | |
$name = $this->option; | |
$placeholder = $this->placeholder; | |
echo "<input type='text' name='". esc_attr( $name ) ."' "; | |
echo "value='". esc_attr( $val ) ."' "; | |
echo "placeholder='". esc_attr( $placeholder ) ."'/> \n"; | |
} | |
// Output <textarea/> | |
function textarea() { | |
assert( 'textarea' === $this->type ); | |
$val = get_option( $this->option ); | |
$name = $this->option; | |
$placeholder = $this->placeholder; | |
echo "<textarea cols='40' rows='8' "; | |
echo "name='". esc_attr( $name ) ."'"; | |
echo "placeholder='". esc_attr( $placeholder ) ."'"; | |
echo '>'. esc_html( $val ) ."</textarea> \n"; | |
} | |
// Output <input type="number"/> | |
function number() { | |
assert( 'number' === (string) $this->type ); | |
$val = get_option( $this->option ); | |
$name = $this->option; | |
$placeholder = $this->placeholder; | |
echo "<input type='number' "; | |
echo "name='". esc_attr( $name ) ."' "; | |
echo "value='". esc_attr( $val ) ."' "; | |
echo "placeholder='". esc_attr( $placeholder ) ."'/> \n"; | |
} | |
// Output <select> | |
function select() { | |
assert( 'select' === (string) $this->type ); | |
$current = (string) get_option( $this->option ); | |
$name = $this->option; | |
echo '<select name="'. esc_attr( $name ) .'"> ' ."\n"; | |
// add all available options | |
foreach ( $this->vals as $key => $val ) { | |
$key = esc_attr( $key ); | |
$val = esc_html( $val ); | |
// whether the current one - will be selected | |
$selected = ( (string) $key === $current ) ? ' selected="selected"' : ''; | |
// output <option> | |
echo '<option value="'. esc_attr( $key ) .'"'. esc_attr( $selected ) .'>'; | |
echo esc_html( $val ); | |
echo '</option>'; | |
echo "\n"; | |
} | |
echo "</select> \n"; | |
} | |
// Output <hr> | |
function hr() { | |
echo '<hr>'; | |
} | |
// $args acessor | |
function __get( $name ) { | |
return isset( $this->args[ $name ] ) ? $this->args[ $name ] : ''; | |
} | |
} | |
/** | |
* A settings section which contains zero or more Field's. | |
* Used internally by Page. | |
* | |
* @author Zachary Scott <zscott.dev@gmail.com> | |
*/ | |
class Section { | |
private $args = array(); | |
private $fields = array(); // all fields in the section | |
public $id; // unique ID of the section | |
public function __construct( $args ) { | |
assert( ! empty( $args ) ); | |
$this->args = $args; | |
// Generate random ID for the section | |
$this->id = uniqid( '_', true ); | |
} | |
/** | |
* Add the given field to the section. | |
* | |
* @param Field $field The field object to add. | |
*/ | |
public function add( $field ) { | |
assert( ! empty( $field ) ); | |
$this->fields[] = $field; | |
} | |
/** | |
* Registers the settings section and its fields with WordPress. | |
* Must be called within 'admin_init' hook. | |
* | |
* @param $page The page to which the section belongs | |
*/ | |
public function build( $page ) { | |
assert( ! empty( $page ) ); | |
$subtext = $this->subtext; | |
// add the settings section | |
add_settings_section( | |
$this->id, | |
$this->title, | |
array( $this, 'subtext' ), | |
$page | |
); | |
// add all section settings | |
foreach ( $this->fields as $field ) { | |
$field->build( $this->id, $page ); | |
} | |
} | |
// Spits out the subtext for the section | |
function subtext() { | |
echo '<p>'. esc_html( $this->subtext ) .'</p>'; | |
} | |
// $args acessor | |
function __get( $name ) { | |
return isset( $this->args[ $name ] ) ? $this->args[ $name ] : ''; | |
} | |
} | |
/** | |
* A settings page - which contains one or more Section's. Each Section | |
* encapsultes zero or more `Field`s. Each field represents a WordPress option | |
* which can be changed. | |
* | |
* Used internally by `SettingsBuilder`. | |
* | |
* @author Zachary Scott <zscott.dev@gmail.com> | |
*/ | |
class Page { | |
// count of all page instances for menu slug | |
private static $count = 1; | |
private $args = array(); | |
private $slug; | |
private $sections; // list of settings sections on the page | |
public function __construct( $args ) { | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'title' => '', | |
'menu' => '', | |
'cap' => 'manage_options', | |
); | |
$this->args = array_merge( $default_args, $args ); | |
$this->slug = plugin_basename( dirname( __FILE__ ) ) .'-settings-'. Page::$count++; | |
} | |
/** | |
* Creates a new section in which to place subsequent settings. | |
* | |
* @param $title - The title of the section to display to the user. | |
*/ | |
public function section( $args ) { | |
assert( ! empty( $args ) ); | |
$this->sections[] = new Section( $args ); | |
} | |
/** | |
* Creates a boolean setting field (checkbox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function bool( $args ) { | |
assert( ! empty( $this->sections ) ); | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'type' => 'bool', | |
); | |
$args = array_merge( $default_args, $args ); | |
$this->add_field( new Field( $args ) ); | |
} | |
/** | |
* Creates a textual setting field (textbox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function text( $args ) { | |
assert( ! empty( $this->sections ) ); | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'type' => 'text', | |
); | |
$args = array_merge( $default_args, $args ); | |
$this->add_field( new Field( $args ) ); | |
} | |
/** | |
* Creates a multi-line textarea setting field (textarea). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function textarea( $args ) { | |
assert( ! empty( $this->sections ) ); | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'type' => 'textarea', | |
); | |
$args = array_merge( $default_args, $args ); | |
$this->add_field( new Field( $args ) ); | |
} | |
/** | |
* Creates a number setting field. | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function number( $args ) { | |
assert( ! empty( $this->sections ) ); | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'type' => 'number', | |
); | |
$args = array_merge( $default_args, $args ); | |
$this->add_field( new Field( $args ) ); | |
} | |
/** | |
* Creates a list of options (combobox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $vals The list of available options | |
* @param string $validate Validation callback | |
*/ | |
public function select( $args ) { | |
assert( ! empty( $this->sections ) ); | |
assert( ! empty( $args ) ); | |
$default_args = array( | |
'type' => 'select', | |
); | |
$args = array_merge( $default_args, $args ); | |
$this->add_field( new Field( $args ) ); | |
} | |
/** Creates a <hr>. */ | |
public function hr() { | |
$args = array( | |
'type' => 'hr', | |
'option' => mt_rand(), | |
); | |
$this->add_field( new Field( $args ) ); | |
} | |
// Adds the given field to the page | |
private function add_field( $field ) { | |
assert( ! empty( $field ) ); | |
$end = sizeof( $this->sections ); | |
$this->sections[ $end - 1 ]->add( $field ); | |
} | |
/** | |
* Registers the options page with WordPress. | |
* Must be called within 'admin_init' hook. | |
*/ | |
public function build() { | |
// register the page w/ wordpress | |
add_action( 'admin_menu', array( $this, 'register_settings_page' ), 999999999 ); | |
// register the settigns sections with wordpress | |
add_action( 'admin_init', array( $this, 'register_settings' ), 999999999 ); | |
} | |
// Registers the settings page w/ WP | |
function register_settings_page() { | |
add_options_page( | |
$this->title, | |
$this->menu, | |
$this->cap, | |
$this->slug, | |
array( $this, 'render' ) | |
); | |
} | |
// Registers the page settings w/ WP | |
public function register_settings() { | |
// build each settings section | |
foreach ( $this->sections as $section ) { | |
$section->build( $this->slug ); | |
} | |
} | |
// Renders the options page | |
public function render() { | |
echo '<h1>' . esc_html( $this->title ) . '</h1> <br>'; | |
// render the options form | |
echo '<form method="post" action="options.php">'; | |
settings_fields( $this->slug ); | |
do_settings_sections( $this->slug ); | |
submit_button(); | |
echo '</form>'; | |
} | |
// $args acessor | |
function __get( $name ) { | |
return isset( $this->args[ $name ] ) ? $this->args[ $name ] : ''; | |
} | |
} | |
/** | |
* Helps build a WordPress settings section with a much nicer interface. Yeah | |
* WordPress's Settings API sucks! | |
* | |
* Can be used like so: | |
* | |
* $settings = new SettingsBuilder(); | |
* | |
* $settings->page( array( | |
* 'title' => 'My Page Title', | |
* 'menu' => 'Test Settings' | |
* ) ); | |
* | |
* $settings->section( array( | |
* 'title' => 'Test Settings' | |
* ) ); | |
* | |
* $settings->text( array( | |
* 'label' => __( 'Textual option', 'text_domain' ), | |
* 'option' => 'text_op' | |
* ) ); | |
* | |
* $settings->bool( array( | |
* 'label' => __( 'Boolean option', 'text_domain' ), | |
* 'option' => 'bool_op' | |
* ) ); | |
* | |
* $settings->select( array( | |
* 'label' => __( 'Select options', 'text_domain' ), | |
* 'option' => 'select_op', | |
* 'vals' => array( | |
* 'test1' => 'Test 1', | |
* 'test2' => 'Test 2', | |
* 'test3' => 'Test 3' | |
* ) | |
* ) ); | |
* | |
* // etc ... | |
* | |
* $settings->build(); | |
* | |
* @author Zachary Scott <zscott.dev@gmail.com> | |
*/ | |
class SettingsBuilder { | |
// list of settings pages | |
private $pages; | |
/** | |
* Creates a settings page on which subsequent sections will be placed. | |
* | |
* @param string $title The title of the settings page. | |
* @param string $menu The menu title | |
* @param string $cap The required capability for page to be visible | |
* (default 'manage_options'). | |
*/ | |
public function page( $args ) { | |
assert( ! empty( $args ) ); | |
// add the page to the list | |
$this->pages[] = new Page( $args ); | |
} | |
/** | |
* Creates a new section in which to place subsequent settings. | |
* | |
* @param string $title The title of the section to display to the user. | |
* @param string $page The theme page to which the section belongs. | |
*/ | |
public function section( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->section( $args ); | |
} | |
/** | |
* Creates a boolean setting field (checkbox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function bool( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->bool( $args ); | |
} | |
/** | |
* Creates a textual setting field (textbox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function text( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->text( $args ); | |
} | |
/** | |
* Creates a multi-line textarea setting field (textarea). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function textarea( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->textarea( $args ); | |
} | |
/** | |
* Creates a number setting field (textbox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $placeholder The placeholder text when no option is selected | |
* @param string $validate Validation callback | |
*/ | |
public function number( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->number( $args ); | |
} | |
/** | |
* Creates a list of options (combobox). | |
* | |
* @param string $label The label to display on the page | |
* @param string $option The option name (wp option API) | |
* @param string $vals The list of available options | |
* @param string $validate Validation callback | |
*/ | |
public function select( $args ) { | |
assert( ! empty( $args ) ); | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->select( $args ); | |
} | |
/** Creates a <hr> */ | |
public function hr() { | |
$end = sizeof( $this->pages ); | |
$this->pages[ $end - 1 ]->hr( array() ); | |
} | |
/** Registers the settings pages, sections and fields with wordpress. */ | |
public function build() { | |
// build each settings page | |
foreach ( $this->pages as $page ) { | |
$page->build(); | |
} | |
} | |
} | |
/** @file SettingsBuilder.php - Simple WP settings builder API | |
* Copyright (c) 2014, 2015 <zscott.dev@gmail.com> | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment