Facilitates WordPress plugin and theme development.
One of the time-consuming part of developing WordPress plugins and themes is creating setting pages. As you more and more write plugins and themes, you will soon realize major part of code can be reused. Admin Page Framework aims to provide reusable code that eliminates the necessity of writing repeated code over and over again.
You will have more organized means of building option pages with the framework. Extend the library class and pass your arrays defining the form elements to the predefined class methods. The library handles all the complex coding behind the scene and creates the pages and the forms for you.
If you are planning to create a product possibly extended with an unlimited number of add-ons, take advantage of the framework’s native extensibility. The created admin pages and forms will become highly extensible with the automatically created hooks. In other words, it empowers other developers to customize your plugin or theme. That will result on making your projects grow.
Also, use the framework as a library and your plugin or theme does not have to require an extra dependency to be installed. Therefore, your product will be perfectly portable.
text
– a normal field to enter text input.password
– a masked text input field.textarea
– a text input field with multiple lines. It supports TinyMCE rich text editor.radio
– a set of radio buttons that lets the user pick an option.checkbox
– a check box that lets the user enable/disable an item.select
– a drop-down list that lest the user pick one or more item(s) from a list.hidden
– a hidden field that will be useful to insert invisible values.file
– a file uploader that lets the user upload files.image
– a custom text field with the image uploader script that lets the user set an image URL.media
– a custom text field with the media uploader script that lets the user set a file URL.color
– a custom text field with the color picker script.submit
– a submit button that lets the user send the form.export
– a custom submit field that lets the user export the stored data.import
– a custom combination field of the file and the submit fields that let the user import data.posttype
– a set of check-lists of taxonomies enabled on the site in a tabbed box.taxonomy
– check-lists of taxonomies enabled on the site in a tabbed box.size
– a combination field of the text and the select fields that let the user set sizes with a selectable unit.section_title
– a text field placed in the section title to let the user name the section.system
– displays the site system information.inline_mixed
– consists of inline elements of fields with different field types.With custom field types, you can create more detailed customized field outputs. The demo component includes the following example custom field types.
sample
– a sample custom field type with a JavaScript script.github
– displays GitHub buttons.path
– lets the user select file paths on the server.toggle
– lets the user toggle a switch button.no_ui_slider
– lets the user set values between ranges with a slider.select2
– lets the user select items from a predefined list which cam be populated with AJAX.post_type_taxonomy
– lets the user select taxonomy terms of selected post types.If you want a field type that are not listed here, you can check the field type pack or request a new one in the forum.
To get started, go to Dashboard -> Admin Page Framework -> About -> Getting Started.
Activate the demo pages to see the possible features of the framework. To activate it, go to Dashboard -> Admin Page Framework -> Add Ons -> Demo.
Notes: this framework does not do anything by itself. If you are not a developer, you do not need this.
The framework internally uses the add_submenu_page()
function to register sub menu pages. When the same page slug is registered for multiple root pages, only the last registered callback gets triggered. The other ones will be ignored.
This means if you choose a very simple page slug such as about
for your plugin/theme’s information page and then if there is another plugin using the same page slug, your users will get either of your page or the other.
To avoid this, make sure to use a unique page slug. One way to do that is to add a prefix like apf_about
.
There is one thing you need to be careful when you include the framework: the framework version conflicts. Imagine you publish a plugin using the framework v3.4.6 and your plugin user installs a plugin using the framework v3.0.0 which is below your framework version. If the other plugin loads earlier than yours, your plugin may not work properly and vice versa.
There is a way to avoid such a conflict: change the PHP class names of the framework you include. All the class names have the prefix AdminPageFramework
so just change it to something like MyPlugin_AdminPageFramework
.
Go to Dashboard -> Admin Page Framework -> Tools -> Generator. Set the prefix in the option field and download the files.
If you do not modify the framework class names, you are supposed to extend the AdminPageFramework
factory class.
class MyAdminPage extends AdminPageFramework { ... }
When you modify the framework class names, make sure you extend the class with the modified name.
class MyAdminPage extends MyPlugin_AdminPageFramework { ... }
For more detailed instruction, go to Dashboard -> Admin Page Framework -> About -> Getting Started.
By the time WordPress’s minimum required PHP version becomes 5.3 or higher, we can use name spaces then this problem will be solved.
The default messages defined by the framework can be changed. For example, when you import a setting with the framework, the setting notice “The options have been updated.” will be displayed.
If you want to change it to something else, modify the oMsg
object. It has the aMessages
public property array holding all the messages that the framework uses.
In each field definition array, you can set the attributes
arguments which defines the HTML attributes of the field so that you can modify the output of the field by passing attribute values.
The argument accepts the values as an array. Each element represents the attribute’s name and value. The array key corresponds to the name of the attribute and the value to the attribute value.
For example,
array( 'field_id' => 'interval', 'title' => __( 'Interval', 'task-scheduler' ), 'type' => 'number', 'attributes' => array( 'min' => 0, 'step' => 1, 'max' => 24, ), ),
In addition, you can change the attributes of the following container elements by setting their key and passing a nested attribute array.
fieldrow
– the td
tag element containing the field output.fieldset
– the fieldset
tag element containing the field output.fields
– the div
tag element containing the sub-fields and the main field.field
– the div
tag element containing each field.This submit button will float right.
array( 'field_id' => 'submit', 'type' => 'submit', 'save' => false, 'value' => __( 'Save', 'task-scheduler' ), 'label_min_width' => 0, 'attributes' => array( 'field' => array( 'style' => 'float:right; clear:none; display: inline;', ), ), )
For meta box and widget form fields (as they have slightly different styling than generic admin pages),
array( 'field_id' => 'submit_in_meta_box', 'type' => 'submit', 'save' => false, 'show_title_column' => false, 'label_min_width' => 0, 'attributes' => array( 'field' => array( 'style' => 'float:right; width:auto;', ), ), ),
To specify a custom size to the preview element of the image
field type, set an attribute array like the below, where 300px is the max width.
array( 'field_id' => 'my_image_field_id', 'title' => __( 'Image', 'admin-page-framework-demo' ), 'type' => 'image', 'attributes' => array( 'preview' => array( 'style' => 'max-width: 200px;', ), ), ),
To display radio button items one per line, set the label_min_width
to 100%
.
array( 'field_id' => 'my_radio_field_id', 'title' => __( 'Radio Button', 'admin-page-framework-demo' ), 'type' => 'radio', 'label_min_width' => '100%', 'label' => array( 'a' => __( 'This is a.', 'admin-page-framework-demo' ), 'b' => __( 'This is b.', 'admin-page-framework-demo' ), 'c' => __( 'This is a.', 'admin-page-framework-demo' )c ), ),
To set the initial value of a field, use the default
argument in the field definition array.
array( 'field_id' => 'my_text_field_id', 'title' => __( 'My Text Input Field', 'admin-page-framework-demo' ), 'type' => 'text', 'default' => 'This text will be displayed for the first time that the field is displayed and will be overridden when a user set an own value.', ),
The value
argument in the definition array can suppress the saved value. This is useful when you want to set a value from a different data source or create a wizard form that stores the data in a custom location.
array( 'field_id' => 'my_text_field_id', 'title' => __( 'My Text Input Field', 'admin-page-framework-demo' ), 'type' => 'text', 'value' => 'This will be always set.', ),
If it is a repeatable field, set values in numerically indexed sub-elements.
array( 'field_id' => 'my_text_field_id', 'title' => __( 'My Text Input Field', 'admin-page-framework-demo' ), 'type' => 'text', 'repeatable' => true, 'value' => 'the first value', array( 'value' => 'the second value', ), array( 'value' => 'the third value', ), ),
Alternately, you may use the options_{instantiated class name}
filter to suppress the options so that setting the value argument is not necessary.
See examples, https://gist.github.com/michaeluno/c30713fcfe0d9d45d89f, https://gist.github.com/michaeluno/fcfac27825aa8a35b90f,
For usage instructions to get started, go to Dashboard -> Admin Page Framework -> About -> Getting Started and create your first plugin.
Text Fields
Selector and Checkboxes
Image, Media, and File Upload
Form Input Verification
Import and Export
Taxonomy and Post Type Checklists
Color Pickers and Buttons
Custom Post Type and Meta Box
Contextual Help Pane
Taxonomy Field
Meta Boxes in Pages Added by Framework
Repeatable Sections, Section Tabs and Section Title Field
Widget Form
What is this for?
This is a PHP class-based WordPress library that helps to create option pages and form fields in the administration area. In addition, it helps to manage to save, export, and import options.
Who needs it?
WordPress plugin/theme developers who publish own products and want to speed up creating setting forms, widgets, contact form etc. and don’t want to require their users to install extra dependencies.
Do my plugin/theme users have to install Admin Page Framework?
No. Include the generated framework files in your distribution package. You can generate your own framework files via Dashboard
-> Admin Page Framework
-> Tools
-> Generator
.
Where can I get the framework files to include?
Go to Dashboard
-> Admin Page Framework
-> Tools
-> Generator
and download the files.
Does my commercial product incorporating your framework library have to be released under GPL2v+?
No. The loader plugin is released under GPLv2 or later but the library itself is released under MIT. Make sure to include only the library file.
Does the framework work with WordPress Multi-site?
Yes, it works with WordPress MU.
Can I set a custom post type as a root page?
Yes. For built-in root menu items or to create your own ones, you need to use the setRootMenuPage()
method. For root pages of custom post types, use setRootMenuPageBySlug()
.
$this->setRootMenuPageBySlug( 'edit.php?post_type=apf_posts' );
How do I retrieve the stored options?
The framework stores them as an organized multidimensional array in the options table in a single row. So use the get_option()
function and pass the instantiated class name as the key or the custom key if you specify one in the constructor.
For instance, if your instantiated class name is APF
then the code would be
$my_options = get_option( 'APF' );
And the option data is formed as an array with a structure like the following.
$my_options = array( // field id => field value 'field_a' => 'value for field a' 'field_b' => 'value for field b' ... // section id => array( // field id => value, // ) 'section_a' => array( 'field_a' => 'value for field_a of section_a', 'field_b' => 'value for field_b of section_b', ... ), 'section_b' => array( 'field_a' => 'value for field_a of section_b', 'field_b' => 'value for field_b of section_b', ... ), ... );
If you are new to PHP, you may feel uncomfortable dealing with multi-dimensional arrays because you would need to call isset()
so many times. The framework has a utility method to help retrieve values of multi-dimensional arrays.
$_oUtil = new AdminPageFramework_WPUtility; $value = $_oUtil->getElement( $my_options, // (required) subject array array( 'key_in_the_first_depth', 'key_in_the_second_depth' ), // (required) dimensional path 'My Default Value Here' // (optional) set your default value in case a value is not set );
So for example, if you need to retrieve the value of field_a
in section_b
, you can do something like this.
$value = $_oUtil->getElement( $my_options, array( 'section_b', 'field_a' ), 'some default value' );
In the framework factory class, you can access the utility object as it is defined already.
$value = $this->oUtil->getElement( $subject, $keys, $default );
Is it possible to use a custom options data for the form instead of the ones used by the framework?
Yes, there are two main means to achieve that.
Use the value
argument in the field definition array to suppress the displaying value in the field.
See an example. https://gist.github.com/michaeluno/fb4088b922b71710c7fb
Override the options array set to the entire form using the options_{instantiated class name}
filter hook or pre-defined method.
See an example. https://gist.github.com/michaeluno/fcfac27825aa8a35b90f
When you go with the second method, make sure to pass an empty string, ''
, to the first parameter of the constructor so that it disables the ability to store submitted form data into the options table.
new MyAdminPage( '' );
How can I add sub-menu pages to the top-level page created by the framework from a separate script?
Say, in your main plugin, your class MyAdminPageClassA
created a top-level page. In your extension plugin, you want to add sub-menu pages from another instance MyAdminPageClassB
.
In the setUp()
method of MyAdminPageClasB
, pass the instantiated class name of the main plugin that created the root menu, MyAdminPageClassA
, to the setRootMenuPageBySlug()
method.
$this->setRootMenuPageBySlug( 'MyAdminPageClassA' );
Another option is to use the set_up_{class name}
action hook. The callback method receives the admin page class object and you can access the framework methods to add sub-menu pages.
class ThirdPartyScript { public function __construct() { add_action( 'set_up_' . 'MyAdminPageClassA', array( $this, 'replyToAddSubMenuPages' ) ); } public function replyToAddSubMenuPages( $oAdminPage ) { $oAdminPage->addSubMenuPage( array( 'page_slug' => 'my_admin_page_b', 'title' => __( 'Example', 'your-text-domain' ), 'order' => 20, ) ); } } new ThirdPartyScript;
See an example.
I want my users to install the loader plugin but do not want to display any visuals of the loader plugin. Is there a way to disable it?
Enable the silent mode of the loader plugin by setting the APFL_SILENT_MODE
constant in your script.
define( 'APFL_SILENT_MODE', true );
Can I create pages in the network admin area?
Yes, See the demo.
Some of my users claim they cannot save options. What would be a possible cause?
max_input_vars
of PHP settings. If this value is small and there are lots of form input elements, the user may not be able to save the options.To increase the value, edit php.ini
and add the following line where 10000
is the increased number.
max_input_vars = 10000
max_allowed_packet
of MySQL settings. Try increasing this value in the my.ini
or my.cnf
file.The 500M
in the following line is where the increased value should be set.
max_allowed_packet=500M
Please keep in mind that these are just a few of many possibilities. If you encounter a situation that prevented the user from saving options, please report.
My class is getting too big by defining predefined callback methods. Is there a way to separate those?
Yes. The predefine method names also serve as a WordPress filter/action hook name. So you can just add callbacks to those hooks from a separate file.
For example, if you want to move your method content_my_page_slug()
, then you would do something like,
function getMyPageContent( $sContent ) { return $sContent . ' additional contents here.'; } add_filter( 'content_my_page_slug', 'getMyPageContent' );
IF you want to move your method load_my_page_slug()
, then you would do something like,
function loadMyPage( $oFactory ) { // do something when the page loads. } add_action( 'load_my_page_slug', 'loadMyPage' );
Custom field types do not seem to show up. What did I do wrong?
Most likely, you have not registered the field type. The check-box in Generator
will include the field type files in the zip archive and their paths in the list for the auto-loader loaded by the framework bootstrap file.
This essentially eliminates the use of include()
or require()
, meaning you can call the custom field type files without using include()
. However, the field type is not registered by itself yet.
In order to use a custom field type, you need to instantiate the field type class by passing the extended framework class name. For example, if your framework class name is MyPlugin_AdminPageFramework
and the field type class name is Select2CustomFieldType
, then you need to do
new Select2CustomFieldType( 'MyPlugin_AdminPageFramework' );
Do this in the setUp()
method in your extended framework class.
public function setUp() { new Select2CustomFieldType( 'MyPlugin_AdminPageFramework' ); }
This enables the select2
custom field type for the class MyPlugin_AdminPageFramework
, not for the other classes. So essentially, do this for every class that uses the field type.
I cannot find what I’d like to do in tutorials and documentation. Where else should I look for more information?
I’ve written a useful class, functions, and even custom field types that will be useful for others! Do you want to include it?
The GitHub repository is available. Raise an issue first and we’ll see if changes can be made.
How can I contribute to this project?
There are various ways to do so. Please refer to the contribution guideline.
How can I contribute to improving the documentation?
You are welcome to submit documentation. Please follow the Documentation Guideline.
In addition, your tutorials and snippets for the framework can be listed in the manual. Let us know it here.
Check out the questions tagged as FAQ on GitHub.
Check out the milestones and issues on GitHub labeled enhancement.
mime_types
argument for the image
and media
field types.setSettingNotice()
of classes extending the post type factory class were not displayed.color
field type by triggering a change event after setting a new value.path
custom field type due to the deprecation of the jQueryFileTree
library and switching to jstree
, which involves deprecation of some arguments and UI improvements.table
built-in field type.contact
built-in field type.selector
argument to the select2
custom field type that enables to show/hide elements on selection.a
tags.width
argument for the tip
field argument.color
field type are hidden by the color picker pallet in recent WordPress versions.tip
field argument made the document width wider than the initial width.save
of the submit
field type to false
.Generator
to Compiler
.email
argument of the submit
field type.See here