My first time encountering object oriented php was probably 2 years ago, when I was preparing a theme to be compatible with WooCommerce, and I stumbled upon classes, $this, private, public and self:: (among other oop keywords), and I must admit I was totally confused. Coming from a non programmer background, this was all new to me. I tried reading more about it, but was always afraid to tackle it.
Notice: This article was written in 2016. WordPress has changed a lot since then, so take this article with a grain of salt…
Plus we rarely used oop in our themes – there was extending the menu walker class, but when you’re only modifying the existing code, you run into a problem of just blindly following what others did, and not fiddling with it too much. Especially if you need to deliver the end product as fast as possible.
This is a trap a lot of self thought programmers fall into – blindly copying code without understanding it what it actually does.
After some time, and raised experience, I released my own plugin, which is written using oop approach. Granted the backbone of the plugin was written on Devin Vinson’s boilerplate, but I had to actually make it work, and by doing that I learned a lot about how classes work, and how to you use them in WordPress.
The inspiration for this tutorial came from something I am currently doing for a firm I’m working for. It’s a Theme Options page. Originally a colleague created it by creating separate .php files, in which he added sub menu pages, created a function which generated the layout, and called it based on saved settings in the database, and provided default settings he made. And it worked nicely. It was a lot of code, but it worked nonetheless. In the meantime I was assigned to review the code, and I also got the design from our designer for the options page. And I had to change a lot of code. A lot. Not only php code, but JavaScript as well.
When I redid the options for the headers (so that they would match the design), I realized that I will have to do this for every subpage there is. And there are 5 similar pages to redo. Plus every page had a different ajax call that would save the option to the database. It was just impractical to do it, and basically waste time on poorly written code. So I remembered the one thing every tutorial will say about oop:
Writing oop code is like writing blueprints to a house – you have your basic elements that will make the house (classes, properties, constants and methods), and from it you can build lots of different houses (class instances).
In my case I want to create a class that will build me a sub menu page, based on it’s name and a set of predefined default values. So every time I create a new instance of that class (a new object), I’ll get a new sub menu page. The basic structure will be the same (names will of course depend on the name I provide), and default values will differ, but I will only have to code that one class. I’ll also only use one ajax callback to fetch my options and save them in the database.
This is so much more efficient, then writing endless code over and over. Basically with any kind of code repetition, you can use oop approach to solve it. That way any changes you need to do will be global, plus you can, if you want to, extend that class and add new methods. The elegance of it is brilliant. Now I’m not saying that we should change every single thing into oop type of programming. Sometimes procedural programming is a good way to go. For a simple code, procedural will probably be easier to code, and to understand. You can read more about procedural vs oop here and here.
Have in mind that I am by no means expert in this field, but I’ll do my best to go step by step and explain as I go. So let’s start.
Laying the php foundations
When creating something big as a theme page, it’s best to put all the files in a separate folder (.php, .js and .css). It’s always better to have a reasonable file structure inside your theme. I’ll be using Twenty Sixteen theme as a base theme, so that you can follow the file structure based on that. Inside the /inc folder we’ll put the /theme-settings folder, which will contain /css and /js folders and theme-settings.php (for now). To have our theme-settings.php file visible to WordPress, we need to include it in the functions.php file.
Find the after_setup_theme action hook, and after it add
require_once( get_template_directory() . '/inc/theme-settings/theme-settings.php' );
Code language: PHP (php)
Now we can start working on out theme settings.
Following the guidelines
Before we start with adding our theme settings, I’d like to talk a bit about WordPress coding standards. They are a certain set of rules that will make your code consistent throughout your theme. Since it’s not really practical to memorize them all, there are few tools that can help you in maintaining those standards – and if you’re submitting a plugin or a theme to WordPress.org, this will make your, and reviewers life a lot easier.
First to mention are linters. Since I’m coding with SublimeText 3, I use jshint and csslint packages as my linters. To install them you’ll need node.js. Just follow the instructions and you’ll be good to go. I talked a bit about them in one of my earlier articles.
The next thing that I’ve only recently found out, and is a tremendous help, is a php code sniffer by squizlabs. The installation of it is a bit tricky on Windows machines, since you’ll either need pear or composer to install it, but after you’ve set it up, it’s a great tool to inspect your php code on the fly. With the code sniffer you’ll want to install the WordPress Coding standards sniffer. Once you’ve set it up in your sublime you’ll get notices what in your code is not up to WordPress coding standards, and you can fix it while you’re writing it :)
It’s a super helpful tool and I recommend that you use it, it will improve your coding style a lot.
Back to the theme settings.
First we’ll add a check to see if the user has the necessary capabilities to access theme settings. Generally this is something only administrators should have access to
add_filter( 'admin_init', 'twentysixteen_theme_settings_capability' );
/**
* Restrict access to the theme settings page to admins
*
* @since 1.0.0
* @return void If user is not administrator they won't see Theme Settings
*/
function twentysixteen_theme_settings_capability() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
}
Code language: PHP (php)
Next, we want to add our settings page. This is necessary so that we can attach subpages to the main Theme Settings page.
add_action( 'admin_menu', 'twentysixteen_theme_settings_add_page' );
/**
* Theme Settings add menu page
*
* @since 1.0.0
* @return void The resulting page's hook_suffix
*/
function twentysixteen_theme_settings_add_page() {
add_menu_page( esc_html__( 'Theme Settings', 'twentysixteen' ), esc_html__( 'Theme Settings', 'twentysixteen' ), 'edit_theme_options', 'twentysixteen_theme_settings', 'twentysixteen_settings_render_page' );
}
Code language: PHP (php)
If you look at the details of add_menu_page function, you’ll notice that fifth argument in the function is the callable function that will render our page, here I’ve created a function that will render the HTML based on what is (or isn’t) found in the database value for the options we are trying to save.
/**
* Theme Settings page builder function
*
* @param string $title The title of the page.
* @param array $values Array of the setting values from the database.
* @return string Returned compiled HTML of the page
*/
function twentysixteen_build_settings_html( $title, $values = null ) {
$out = '';
$value = 0;
$checked = '';
$maps_enabled = ( isset( $values ) && '' !== $values ) ? $values->google_maps_enable : '';
if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
$value = 1;
$checked = 'checked';
}
$out .= '<h3>' . esc_html__( 'Settings', 'twentysixteen' ) . '</h3>
<div class="twentysixteen_options_wrapper">
<h4>' . esc_html__( 'Enable Google Maps', 'twentysixteen' ) . '</h4>
<input type="hidden" class="twentysixteen_setting google_maps_enable" name="google_maps_enable" value="' . $value . '">
<label class="checkbox_label" for="google_maps_enable" data-settings=".twentysixteen_google_maps_api_key"><span class="twentysixteen_setting checkbox ' . $checked . '"></span>' . esc_html__( 'Enable google map', 'twentysixteen' ) . '</label>
<p class="info">' . esc_html__( 'Use this if you are not using external plugin to power the Google Maps . ', 'twentysixteen' ) . '</p>
</div>';
if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key show">
<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="' . esc_attr( $values->google_api_key ) . '" />
<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
</div>';
} else {
$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key" style="display:none;">
<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="" />
<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
</div>';
}
return $out;
}
/**
* Theme Settings page render function
*
* @return void
*/
function twentysixteen_settings_render_page() {
?>
<div class="wrap">
<h2 class="page_title"><?php esc_html_e( 'Theme Settings', 'twentysixteen' ) ?></h2>
<p class="description"><?php esc_html_e( 'General theme settings', 'twentysixteen' ) ?></p>
<div class="settings_above_meta">
<a href="#" class="save_all" id="twentysixteen_settings_save"><?php esc_html_e( 'Save All', 'twentysixteen' ) ?></a>
<span class="spinner"></span><span class="saved_options"></span>
</div>
<div class="theme_settings_inner_content">
<?php
$twentysixteen_settings = get_option( 'twentysixteen_settings', '' );
if ( isset( $twentysixteen_settings ) && '' !== $twentysixteen_settings ) {
foreach ( $twentysixteen_settings as $key => $values ) {
echo twentysixteen_build_settings_html( 'Settings', $values ); // WPCS: XSS ok.
}
} else {
echo twentysixteen_build_settings_html( 'Settings' ); // WPCS: XSS ok.
}
wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' ); ?>
</div>
</div><?php
}
Code language: HTML, XML (xml)
Here I’ve added a ‘dummy’ google maps control. Before we turn to styling and JavaScript, which are kinda essential here (I’ll explain this in a second), let’s add the ajax callback function, and let’s enqueue our style and script, as well as few localizations
add_action( 'wp_ajax_twentysixteen_settings_save', 'twentysixteen_settings_save_callback' );
/**
* Settings save AJAX callback function
*
* @return void
*/
function twentysixteen_settings_save_callback() {
if ( isset( $_POST['data'], $_POST['twentysixteen_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['twentysixteen_settings_nonce'] ), 'twentysixteen_settings_nonce_action' ) && '' !== $_POST['data'] ) { // Input var okay.
$twentysixteen_settings = json_decode( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ); // Input var okay.
update_option( 'twentysixteen_settings', $twentysixteen_settings );
}
wp_die();
}
add_action( 'admin_enqueue_scripts', 'twentysixteen_theme_settings_admin_scripts' );
/**
* Enqueue style and scripts for Theme Settings page
*
* @since 1.0.0
* @param string $hook Page hook suffix where the scripts and styles should be loaded.
* @return void
*/
function twentysixteen_theme_settings_admin_scripts( $hook ) {
$screen = get_current_screen();
$screen_id = $screen->id;
if ( strpos( $screen_id, 'page_twentysixteen_theme' ) !== false ) {
wp_enqueue_style( 'twentysixteen_theme_settings_css', get_template_directory_uri() . '/inc/theme-settings/css/settings-style.css', '', '1.0.0' );
wp_enqueue_script( 'twentysixteen_theme_settings_js', get_template_directory_uri() . '/inc/theme-settings/js/settings-custom.js', array( 'jquery' ), '1.0.0', true );
wp_localize_script( 'twentysixteen_theme_settings_js', 'twentysixteen_settings_object', array(
'saved' => esc_html__( 'Settings Saved', 'twentysixteen' ),
'delete' => esc_html__( 'Delete', 'twentysixteen' ),
'save' => esc_html__( 'Save', 'twentysixteen' ),
) );
}
}
Code language: PHP (php)
You may notice a few comments here and there. These are comments that notify the php code sniffer that the echoed variables are safe, and need no escaping (or sanitizing in the case of global $_POST variables). You can read more about it here.
Ok, so now that we have all of our php code in, you may wonder a few things: 1. Where is the oop approach here?! 2. There is no checkbox, and the input field is hidden, what’s up with that?!
First one – this isn’t object oriented approach, glad you caught that one :D This is pure procedural code. When you’re creating a page, and including few underlying necessities (enqueuing scripts etc.), you don’t really need oop approach. No one is stopping you from creating a class here, define all your methods here and then instantiating it. But I don’t think that would benefit you much. We won’t be repeating this part of the code, so there is no real need of using oop here. We’ll get to that later on, don’t worry :)
Second – I told you that styling and JavaScript are kinda important, no? I personally don’t like the bare basic HTML controls. Regular checkboxes, radio buttons and input fields are so boring and ugly. So I’ve decided to spice it up a bit.
So create your settings-style.css file in the /css sub folder and add the following code
/*************** 1. Theme Settings General ***************/
.theme_settings_inner_content {
padding: 30px;
background: #fff;
margin-top: 20px;
}
.settings_above_meta .save_all {
text-decoration: none;
background: #ddd;
border-radius: 3px;
margin-top: 15px;
text-transform: uppercase;
padding: 8px 10px;
display: inline-block;
color: #4e4a4a;
-webkit-transition: all 200ms ease-in;
transition: all 200ms ease-in;
}
.settings_above_meta .save_all:hover {
background: #ccc;
}
.settings_above_meta .save_all:active,
.settings_above_meta .save_all:focus {
border: 0;
box-shadow: none;
outline: 0;
}
.settings_above_meta .spinner {
background: url(spinner.gif) no-repeat;
-webkit-background-size: 20px 20px;
background-size: 20px 20px;
display: inline-block;
visibility: hidden;
float:none;
vertical-align: middle;
opacity: .7;
filter: alpha(opacity=70);
width: 20px;
height: 20px;
margin: -2px 10px 0;
}
.settings_above_meta .saved_options {
color: #3eb72f;
font-weight: 600;
text-transform: uppercase;
}
/*****---------- 1.1 Checkbox ----------*****/
input[type="checkbox"].twentysixteen_setting {
display: none;
}
.checkbox_label{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.twentysixteen_setting.checkbox {
width: 25px;
height: 25px;
background: #fff;
border: 1px solid #ddd;
border-radius: 3px;
margin-right: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
}
.twentysixteen_setting.checkbox:before {
content: '✔';
color: transparent;
position: absolute;
top: 5px;
left: 6px;
font-size: 19px;
line-height: 0.8;
-webkit-transition: all 150ms ease-in;
transition: all 150ms ease-in;
}
.twentysixteen_setting.checkbox.checked:before {
content: '✔';
color: #2bb1ef;
}
/*****---------- 1.2 Input Field ----------*****/
.twentysixteen_options_wrapper input[type="text"] {
background: #fff;
border: 1px solid #ddd;
padding: 3px 10px;
border-radius: 3px;
box-shadow: none;
}
.twentysixteen_options_wrapper input[type="text"]:active,
.twentysixteen_options_wrapper input[type="text"]:focus {
border: 1px solid #ddd;
box-shadow: none;
outline: 0;
}
Code language: CSS (css)
And also add your JavaScript in settings-custom.js file in the /js sub folder
jQuery( document ).ready(function( $) {
"use strict";
$( document )
.on('click', '#twentysixteen_settings_save', settings_save )
.on('click', '.checkbox_label', checkbox_switch );
/********* Checkbox Switch ***********/
function checkbox_switch(e) {
e.preventDefault();
var $this = $(this);
var utter_hide_layout = $this.data('settings');
var $hidden_input = $this.prev('input');
var $checkbox = $this.find('.checkbox');
if ( $checkbox.hasClass('checked') ) {
$checkbox.removeClass('checked');
$hidden_input.val('0');
$( utter_hide_layout ).hide();
} else {
$checkbox.addClass('checked');
$hidden_input.val('1');
$( utter_hide_layout ).show();
}
}
function settings_save(e) {
e.preventDefault();
var $saved = $('.settings_above_meta .saved_options');
var $spinner = $('.settings_above_meta .spinner');
var settings_out = {};
settings_out['settings'] = {};
settings_out['settings']['google_api_key'] = $('.twentysixteen_options_wrapper .google_api_key').val();
settings_out['settings']['google_maps_enable'] = $('.twentysixteen_options_wrapper .google_maps_enable').val();
$.ajax({
type: 'POST',
url: ajaxurl,
data: {
'action' : 'twentysixteen_settings_save',
'data' : JSON.stringify( settings_out, null, 2 ),
'twentysixteen_settings_nonce' : $('#twentysixteen_settings_nonce').val()
},
success: function(data) {
$saved.text( twentysixteen_settings_object.saved ).delay( 2000 ).fadeOut();
},
beforeSend : function () {
$saved.text('').show();
$spinner.css('visibility', 'visible');
},
error : function (jqXHR, textStatus, errorThrown) {
$loader.html( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
},
complete : function () {
$spinner.css('visibility', 'hidden');
}
});
}
});
Code language: JavaScript (javascript)
Here we added two on click events. One is the checkbox toggle that will look for a settings data attribute in the checkbox label, and based on that will toggle the visibility of the input field – why show the field that cannot be used if you haven’t enabled the setting, right? The second event is the ajax save. It looks for the input fields, fetches their values and stores it in an object that you’ll convert to a JSON string. Also don’t forget your nonces. Always make sure that you write secure code – escaping on output and sanitizing the input is really important.
With all of that our complete code looks like
<?php
/**
* Theme Settings
*
* @package WordPress
* @subpackage twentysixteen/inc/theme-settings
* @version 1.0.0
* @author Made by Denis <https://madebydenis.com/>
* @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
* @link https://twentysixteen.io
* @since 1.0.0
*/
/**
* Theme Settings
*
* @package WordPress
* @subpackage twentysixteen/inc/theme-settings
* @version 1.0.0
* @author Made by Denis <https://madebydenis.com/>
* @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
* @link https://twentysixteen.io
* @since 1.0.0
*/
add_filter( 'admin_init', 'twentysixteen_theme_settings_capability' );
/**
* Restrict access to the theme settings page to admins
*
* @since 1.0.0
* @return void If user is not administrator they won't see Theme Settings
*/
function twentysixteen_theme_settings_capability() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
}
add_action( 'admin_menu', 'twentysixteen_theme_settings_add_page' );
/**
* Theme Settings add menu page
*
* @since 1.0.0
* @return void The resulting page's hook_suffix
*/
function twentysixteen_theme_settings_add_page() {
add_menu_page( esc_html__( 'Theme Settings', 'twentysixteen' ), esc_html__( 'Theme Settings', 'twentysixteen' ), 'edit_theme_options', 'twentysixteen_theme_settings', 'twentysixteen_settings_render_page' );
}
/**
* Theme Settings page builder function
*
* @param string $title The title of the page.
* @param array $values Array of the setting values from the database.
* @return string Returned compiled HTML of the page
*/
function twentysixteen_build_settings_html( $title, $values = null ) {
$out = '';
$value = 0;
$checked = '';
$maps_enabled = ( isset( $values ) && '' !== $values ) ? $values->google_maps_enable : '';
if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
$value = 1;
$checked = 'checked';
}
$out .= '<h3>' . esc_html__( 'Settings', 'twentysixteen' ) . '</h3>
<div class="twentysixteen_options_wrapper">
<h4>' . esc_html__( 'Enable Google Maps', 'twentysixteen' ) . '</h4>
<input type="hidden" class="twentysixteen_setting google_maps_enable" name="google_maps_enable" value="' . $value . '">
<label class="checkbox_label" for="google_maps_enable" data-settings=".twentysixteen_google_maps_api_key"><span class="twentysixteen_setting checkbox ' . $checked . '"></span>' . esc_html__( 'Enable google map', 'twentysixteen' ) . '</label>
<p class="info">' . esc_html__( 'Use this if you are not using external plugin to power the Google Maps . ', 'twentysixteen' ) . '</p>
</div>';
if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key show">
<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="' . esc_attr( $values->google_api_key ) . '" />
<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
</div>';
} else {
$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key" style="display:none;">
<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="" />
<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
</div>';
}
return $out;
}
/**
* Theme Settings page render function
*
* @return void
*/
function twentysixteen_settings_render_page() {
?>
<div class="wrap">
<h2 class="page_title"><?php esc_html_e( 'Theme Settings', 'twentysixteen' ) ?></h2>
<p class="description"><?php esc_html_e( 'General theme settings', 'twentysixteen' ) ?></p>
<div class="settings_above_meta">
<a href="#" class="save_all" id="twentysixteen_settings_save"><?php esc_html_e( 'Save All', 'twentysixteen' ) ?></a>
<span class="spinner"></span><span class="saved_options"></span>
</div>
<div class="theme_settings_inner_content">
<?php
$twentysixteen_settings = get_option( 'twentysixteen_settings', '' );
if ( isset( $twentysixteen_settings ) && '' !== $twentysixteen_settings ) {
foreach ( $twentysixteen_settings as $key => $values ) {
echo twentysixteen_build_settings_html( 'Settings', $values ); // WPCS: XSS ok.
}
} else {
echo twentysixteen_build_settings_html( 'Settings' ); // WPCS: XSS ok.
}
wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' ); ?>
</div>
</div><?php
}
add_action( 'wp_ajax_twentysixteen_settings_save', 'twentysixteen_settings_save_callback' );
/**
* Settings save AJAX callback function
*
* @return void
*/
function twentysixteen_settings_save_callback() {
if ( isset( $_POST['data'], $_POST['twentysixteen_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['twentysixteen_settings_nonce'] ), 'twentysixteen_settings_nonce_action' ) && '' !== $_POST['data'] ) { // Input var okay.
$twentysixteen_settings = json_decode( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ); // Input var okay.
update_option( 'twentysixteen_settings', $twentysixteen_settings );
}
wp_die();
}
add_action( 'admin_enqueue_scripts', 'twentysixteen_theme_settings_admin_scripts' );
/**
* Enqueue style and scripts for Theme Settings page
*
* @since 1.0.0
* @param string $hook Page hook suffix where the scripts and styles should be loaded.
* @return void
*/
function twentysixteen_theme_settings_admin_scripts( $hook ) {
$screen = get_current_screen();
$screen_id = $screen->id;
if ( strpos( $screen_id, 'page_twentysixteen_theme' ) !== false ) {
wp_enqueue_style( 'twentysixteen_theme_settings_css', get_template_directory_uri() . '/inc/theme-settings/css/settings-style.css', '', '1.0.0' );
wp_enqueue_script( 'twentysixteen_theme_settings_js', get_template_directory_uri() . '/inc/theme-settings/js/settings-custom.js', array( 'jquery' ), '1.0.0', true );
wp_localize_script( 'twentysixteen_theme_settings_js', 'twentysixteen_settings_object', array(
'saved' => esc_html__( 'Settings Saved', 'twentysixteen' ),
'delete' => esc_html__( 'Delete', 'twentysixteen' ),
'save' => esc_html__( 'Save', 'twentysixteen' ),
) );
}
}
Code language: HTML, XML (xml)
And renders out like this
We’ve only scratched the surface here. And the object oriented programming is yet to come, but don’t be alarmed, we will get to it in the next part.
I’d like to mention that the settings on the main screen should be some global settings that you set – kinda like our google maps API key in the example above. You can save them ‘by hand’ (manually writing it in JavaScript), or you can check the input fields that have certain class (.twentysixteen_setting for instance), and save them in JavaScript by going through each element with that class. I’ve done it this way because there are only 2 options to save, but you can customize this to your liking.
This is it for now, I’ll write up a second part soon where we’ll see how we can add sub pages using classes and object oriented approach. Stay tuned, and until then happy coding :)
Leave a Reply