In a previous series, I provided an in-depth guide to working with the WordPress Settings API. For those who are new to WordPress or who have been using other tools such as The Customizer to handle various options, it may be something that you have not had to use in your theme or plugin development.
As stated in the Codex:
The Settings API, added in WordPress 2.7, allows admin pages containing settings forms to be managed semi-automatically. It lets you define settings pages, sections within those pages and fields within the sections.
I don't think it's something that's required to learn, but it's something that you should know exists and know how to work with it if you find yourself needing to introduce option pages into the WordPress administration area.
It's a powerful, albeit somewhat complex, API that provides us with a lot of functionality. Ultimately, it allows us to do a lot of work on the server side and minimal work on the client side.
But what about the times when we're working with a custom solution for clients and we need a little more flexibility than the Settings API provides? For example, say we need to build a plugin that will have a settings page but needs a more flexible set of options and tailored validation functionality?
In those cases, it's possible to write our own custom WordPress administration pages. In this series, we're going to take a look at how to do exactly that.
As with most tutorials like this, it's important to make sure that you have everything in place to follow along so that you can work with the source code that we cover throughout the series.
For this tutorial, I'm assuming:
If you're not familiar with how to set up a local development environment that includes WordPress, please see this series for how to do just that.
And if you're relatively comfortable with PHP, even if it's just reading the language, then I'll do the best I can to provide clear instructions and comments for each bit of code that we share.
Once all of this is in place, we're ready to begin working on our plugin.
By the end of this series, we're going to have a plugin that meets the following requirements:
Furthermore, we'll make sure that we approach this in the most modular way possible using the WordPress Coding Standards and similar practices to make reading, writing, and maintaining our plugin as easy as possible.
The first thing that we need to do is to create the plugin bootstrap. This will include creating a directory to house the plugin's files, a basic README, a copy of the license, a bootstrap file that will eventually be used to start the plugin, and a directory that will be used to hold the classes related to the administrative functionality.
The files are available for download as an attachment to this post but, in the meantime, you can see what my directory looks like below:

Furthermore, the contents of the plugin bootstrap are simple. Review the following code for the single PHP file custom-admin-settings.php, and then I'll discuss it in more detail below the block.
<?php
/**
* The plugin bootstrap file
*
* This file is read by WordPress to generate the plugin information in the
* plugin admin area. This file also defines a function that starts the plugin.
*
* @link http://code.tutsplus.com/tutorials/creating-custom-admin-pages-in-wordpress-1
* @since 1.0.0
* @package Custom_Admin_Settings
*
* @wordpress-plugin
* Plugin Name: Custom Admin Settings
* Plugin URI: http://code.tutsplus.com/tutorials/creating-custom-admin-pages-in-wordpress-1
* Description: Demonstrates how to write custom administration pages in WordPress.
* Version: 1.0.0
* Author: Tom McFarlin
* Author URI: https://tommcfarlin.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
add_action( 'plugins_loaded', 'tutsplus_custom_admin_settings' );
/**
* Starts the plugin.
*
* @since 1.0.0
*/
function tutsplus_custom_admin_settings() {
}
Notice that in the code above, there's actual very little code. Instead, it's a lot of comments. The main block of comments at the top of the file explains what the file does.
The area below the @wordpress-plugin tag is what WordPress will read in order to generate the plugin's title, description, and relative links in the plugin dashboard of WordPress.
Next, we prevent anyone from accessing the file directly. And, finally, we create a custom function to be fired with the plugins_loaded hook. This function is what will be used to start the plugin.
At this point, you should be able to log in to WordPress, navigate to the Plugin's Dashboard, and then see the plugin available to activate. Go ahead and click Activate.
Nothing will happen yet, but we'll start adding functionality as we work throughout this tutorial.
In order to begin working on the plugin, let's first introduce a submenu item. To do this, we'll need to take advantage of the WordPress API function add_options_page. This function will require five parameters:
Note that we'll be using classes to organize our functionality, so much of what we're doing is going to be object-oriented.
First, let's create a class in the admin directory called class-submenu.php. Since this class is responsible for introducing a new submenu, we'll have it named descriptively.
The contents of the class should look like this:
<?php
/**
* Creates the submenu item for the plugin.
*
* @package Custom_Admin_Settings
*/
/**
* Creates the submenu item for the plugin.
*
* Registers a new menu item under 'Tools' and uses the dependency passed into
* the constructor in order to display the page corresponding to this menu item.
*
* @package Custom_Admin_Settings
*/
class Submenu {
/**
* A reference the class responsible for rendering the submenu page.
*
* @var Submenu_Page
* @access private
*/
private $submenu_page;
/**
* Initializes all of the partial classes.
*
* @param Submenu_Page $submenu_page A reference to the class that renders the
* page for the plugin.
*/
public function __construct( $submenu_page ) {
$this->submenu_page = $submenu_page;
}
/**
* Adds a submenu for this plugin to the 'Tools' menu.
*/
public function init() {
add_action( 'admin_menu', array( $this, 'add_options_page' ) );
}
/**
* Creates the submenu item and calls on the Submenu Page object to render
* the actual contents of the page.
*/
public function add_options_page() {
add_options_page(
'Tuts+ Custom Administration Page',
'Custom Administration Page',
'manage_options',
'custom-admin-page',
array( $this->submenu_page, 'render' )
);
}
}
At this point, the plugin will still not do anything. We still need to create the actual Submenu_Page class, and then we need to wire the classes up to the bootstrap file.
Let's start with the Submenu_Page class first. Create another file in the admin directory and call it class-submenu-page.php. Then, in the file, add the following code.
<?php
/**
* Creates the submenu page for the plugin.
*
* @package Custom_Admin_Settings
*/
/**
* Creates the submenu page for the plugin.
*
* Provides the functionality necessary for rendering the page corresponding
* to the submenu with which this page is associated.
*
* @package Custom_Admin_Settings
*/
class Submenu_Page {
/**
* This function renders the contents of the page associated with the Submenu
* that invokes the render method. In the context of this plugin, this is the
* Submenu class.
*/
public function render() {
echo 'This is the basic submenu page.';
}
}
When this page renders, it will simply display the text: "This is the basic submenu page." We'll eventually get into adding new options. But first, let's bring this plugin to life by instantiating it within our bootstrap file.
Next, open the custom-admin-settings.php file that we created earlier in this tutorial. Let's go ahead and write the code necessary to introduce the new submenu item and its associated page.
Remember, the Submenu class requires that an instance of the Submenu_Page class be passed into its constructor, and then we need to call the init method on the Submenu class to set the whole thing into motion.
In code, this looks like the following:
<?php
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
// Include the dependencies needed to instantiate the plugin.
foreach ( glob( plugin_dir_path( __FILE__ ) . 'admin/*.php' ) as $file ) {
include_once $file;
}
add_action( 'plugins_loaded', 'tutsplus_custom_admin_settings' );
/**
* Starts the plugin.
*
* @since 1.0.0
*/
function tutsplus_custom_admin_settings() {
$plugin = new Submenu( new Submenu_Page() );
$plugin->init();
}At this point, you should be able to refresh your installation of WordPress, activate the plugin (if it's not already activated), and then see your new page rendered within the administration area.

In the next article, we'll look at how we can begin introducing actual settings into the screen. Additionally, we'll look at some best practices in terms of working with our template and our template partials, and then we'll see how they will be wired up to the APIs responsible for not only saving them but how we will sanitize and validate them.
But before we go that far, I want to talk a little bit about the class design that we've seen in this tutorial. Generally speaking, I want to talk about why we have a class for the Submenu and the Submenu_Page and how it relates to the bootstrap file.
For those of you who are familiar with the Single Responsibility Principle, this section may not be of any interest to you. But if who need a refresher or want to hear more, then read on.
Gather together the things that change for the same reasons. Separate those things that change for different reasons.
There's more much to this, but if you were to look at each of our classes (at least the two we have thus far), then it's clear that the reasons our classes may change are as follows:
The above two reasons are two very different reasons that classes may change, so keeping them together in the same class would violate the above principle.
Ultimately, I bring this up not only to help shed light on greater software engineering principles that can be applied in WordPress, but also to help prepare you for some of the reasons we're going to be breaking apart certain things that are usually large files within the context of plugins.
The nice thing about learning principles is that they can be applied in multiple projects and not just in single projects. You learn them, you practice using them, and you get better at architecting solutions for other people.
The learning curve may be steep, but once you begin that uphill climb, it gets easier and easier to incorporate the principles into your day-to-day work. Then, the work you're providing for others becomes much easier to maintain over time.
Don't forget that you can download the plugin in its current state from this post. As we progress through the series, I'll make the latest version available on each post so you will be able to follow along with the code covered in each tutorial, tinker with it, and prepare questions that you may want to ask in the comments.
As a side note, if you're looking for other utilities to help you build out your growing set of tools for WordPress or for code to study and become more well-versed in WordPress, don't forget to see what we have available in Envato Market.
Remember, you can catch all of my courses and tutorials on my profile page, and you can follow me on my blog and/or Twitter at @tommcfarlin where I talk about various software development practices and how we can employ them in WordPress.
Finally, don't hesitate to leave any questions or comments in the feed below. I do my best to participate and answer every question or critique you offer as it relates to this project.
The Best Small Business Web Designs by DesignRush
/
2Create Modern Vue Apps Using Create-Vue and Vite
/
9How to Fix the “There Has Been a Critical Error in Your Website” Error in WordPress
/
3How To Fix The “There Has Been A Critical Error in Your Website” Error in WordPress
How to Create a Privacy Policy Page in WordPress
/
7WordPress Website Maintenance Guide For Beginners
/
8How Long Does It Take to Learn JavaScript?
/
-1How Long Does it Take to Learn JavaScript
/
1The Best Way to Deep Copy an Object in JavaScript
/
-1
4
-5Adding and Removing Elements From Arrays in JavaScript
/
-3Create a JavaScript AJAX Post Request: With and Without jQuery
/
95 Real-Life Uses for the JavaScript reduce() Method
/
-9How to Enable or Disable a Button With JavaScript: jQuery vs. Vanilla
/
4How to Enable or Disable a Button With JavaScript: jQuery vs Vanilla
/
-5Confirm Yes or No With JavaScript
/
-4How to Change the URL in JavaScript: Redirecting
/
-127 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
1321 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
-1130 HTML Best Practices for Beginners
/
-731 Best WordPress Calendar Plugins and Widgets (With 5 Free Plugins)
25 Ridiculously Impressive HTML5 Canvas Experiments
/
-3
1How to Implement Email Verification for New Members
/
2How to Create a Simple Web-Based Chat Application
/
630 Popular WordPress User Interface Elements
/
-2Top 18 Best Practices for Writing Super Readable Code
/
1Best Affiliate WooCommerce Plugins Compared
/
-1118 Best WordPress Star Rating Plugins
/
1410+ Best WordPress Twitter Widgets
/
220+ Best WordPress Booking and Reservation Plugins
/
4Working With Tables in React: Part Two
/
-3Best CSS Animations and Effects on CodeCanyon
/
-1730 CSS Best Practices for Beginners
/
3How to Create a Custom WordPress Plugin From Scratch
/
410 Best Responsive HTML5 Sliders for Images and Text… and 3 Free Options
/
-616 Best Tab and Accordion Widget Plugins for WordPress
/
-818 Best WordPress Membership Plugins and 5 Free Plugins
/
425 Best WooCommerce Plugins for Products, Pricing, Payments and More
/
110 Best WordPress Twitter Widgets
1 /
1012 Best Contact Form PHP Scripts for 2020
/
-220 Popular WordPress User Interface Elements
/
-410 Best WordPress Star Rating Plugins
/
-412 Best CSS Animations on CodeCanyon
/
-212 Best WordPress Booking and Reservation Plugins
/
120 Best WordPress Calendar Plugins and Widgets
/
-412 Elegant CSS Pricing Tables for Your Latest Web Project
/
924 Best WordPress Form Plugins for 2020
/
-2Getting Started With Django: Newly Updated Course
/
-1Create a Blog for Each Category or Department in Your WooCommerce Store
/
48 Best WordPress Booking and Reservation Plugins
/
-15Best Exit Popups for WordPress Compared
/
18Best Exit Popups for WordPress Compared
/
-311 Best Tab & Accordion WordPress Widgets & Plugins
/
-1012 Best Tab & Accordion WordPress Widgets & Plugins
1 /
1New Course: Practical React Fundamentals
/
2Short Course: Better Angular App Architecture With Modules
/
1Preview Our New Course on Angular Material
/
3Build Your Own CAPTCHA and Contact Form in PHP
/
-3Object-Oriented PHP With Classes and Objects
/
1Best Practices for ARIA Implementation
/
-5Accessible Apps: Barriers to Access and Getting Started With Accessibility
/
-4Dramatically Speed Up Your React Front-End App Using Lazy Loading
/
1615 Best Modern JavaScript Admin Templates for React, Angular, and Vue.js
/
-1615 Best Modern JavaScript Admin Templates for React, Angular and Vue.js
/
319 Best JavaScript Admin Templates for React, Angular, and Vue.js
/
2New Course: Build an App With JavaScript and the MEAN Stack
/
10Hands-on With ARIA: Accessibility Recipes for Web Apps
/
410 Best WordPress Facebook Widgets
13Hands-on With ARIA: Accessibility for eCommerce
/
6New eBooks Available for Subscribers
/
-8Hands-on With ARIA: Homepage Elements and Standard Navigation
/
11
-5Site Accessibility: Getting Started With ARIA
/
5How Secure Are Your JavaScript Open-Source Dependencies?
/
-2New Course: Secure Your WordPress Site With SSL
/
-2Testing Components in React Using Jest and Enzyme
/
-8Testing Components in React Using Jest: The Basics
/
-515 Best PHP Event Calendar and Booking Scripts
/
-3Create Interactive Gradient Animations Using Granim.js
/
11How to Build Complex, Large-Scale Vue.js Apps With Vuex
1 /
-3Examples of Dependency Injection in PHP With Symfony Components
/
-6Set Up Routing in PHP Applications Using the Symfony Routing Component
1 /
9A Beginner’s Guide to Regular Expressions in JavaScript
/
7Introduction to Popmotion: Custom Animation Scrubber
/
-6Introduction to Popmotion: Pointers and Physics
/
-10New Course: Connect to a Database With Laravel’s Eloquent ORM
/
-7How to Create a Custom Settings Panel in WooCommerce
/
-13Building the DOM faster: speculative parsing, async, defer and preload
1 /
420 Useful PHP Scripts Available on CodeCanyon
3 /
51How to Find and Fix Poor Page Load Times With Raygun
/
1Introduction to the Stimulus Framework
/
-12Single-Page React Applications With the React-Router and React-Transition-Group Modules
712 Best Contact Form PHP Scripts
1 /
-3Getting Started With the Mojs Animation Library: The ShapeSwirl and Stagger Modules
Getting Started With the Mojs Animation Library: The Shape Module
/
-1Getting Started With the Mojs Animation Library: The HTML Module
/
3Project Management Considerations for Your WordPress Project
/
-98 Things That Make Jest the Best React Testing Framework
/
5Creating an Image Editor Using CamanJS: Layers, Blend Modes, and Events
/
1New Short Course: Code a Front-End App With GraphQL and React
/
1Creating an Image Editor Using CamanJS: Applying Basic Filters
/
-11Creating an Image Editor Using CamanJS: Creating Custom Filters and Blend Modes
/
-1Modern Web Scraping With BeautifulSoup and Selenium
/
1Challenge: Create a To-Do List in React
1 /
-2Deploy PHP Web Applications Using Laravel Forge
/
-3Getting Started With the Mojs Animation Library: The Burst Module
/
4
-910 Things Men Can Do to Support Women in Tech
/
-2A Gentle Introduction to Higher-Order Components in React: Best Practices
/
-5A Gentle Introduction to HOC in React: Learn by Example
/
1A Gentle Introduction to Higher-Order Components in React
/
-7Creating Pretty Popup Messages Using SweetAlert2
/
7Creating Stylish and Responsive Progress Bars Using ProgressBar.js
/
1618 Best Contact Form PHP Scripts for 2022
/
-2How to Make a Real-Time Sports Application Using Node.js
/
-3Creating a Blogging App Using Angular & MongoDB: Delete Post
/
-18Set Up an OAuth2 Server Using Passport in Laravel
/
1Creating a Blogging App Using Angular & MongoDB: Add Post
/
-1Introduction to Mocking in Python
/
1Creating a Blogging App Using Angular & MongoDB: Show Post
/
9Creating a Blogging App Using Angular & MongoDB: Home
/
6
3Creating a Blogging App Using Angular & MongoDB: Login
/
12Creating Your First Angular App: Implement Routing
/
12Persisted WordPress Admin Notices: Part 4
/
-2Creating Your First Angular App: Components, Part 2
/
3Persisted WordPress Admin Notices: Part 3
/
4How Laravel Broadcasting Works
/
-1
7Persisted WordPress Admin Notices: Part 2
/
-2Create Your First Angular App: Storing and Accessing Data
/
5Persisted WordPress Admin Notices: Part 1
/
-1Error and Performance Monitoring for Web & Mobile Apps Using Raygun
/
5Using Luxon for Date and Time in JavaScript
7 /
-3How to Create an Audio Oscillator With the Web Audio API
/
-8How to Cache Using Redis in Django Applications
/
220 Essential WordPress Utilities to Manage Your Site
/
-4Introduction to API Calls With React and Axios
/
13Beginner’s Guide to Angular 4: HTTP
/
13Rapid Web Deployment for Laravel With GitHub, Linode, and RunCloud.io
/
7Beginners Guide to Angular 4: Routing
/
-10Beginner’s Guide to Angular 4: Services
/
1Beginner’s Guide to Angular 4: Components
/
1Creating a Drop-Down Menu for Mobile Pages
/
9Introduction to Forms in Angular 4: Writing Custom Form Validators
/
5Getting Started With Redux: Connecting Redux With React
/
12Getting Started With Redux: Learn by Example
/
14Getting Started With Redux: Why Redux?
/
11How to Auto Update WordPress Salts
/
-4How to Download Files in Python
/
-2
-19Eloquent Mutators and Accessors in Laravel
1 /
15
-11
1310 Best HTML5 Sliders for Images and Text
/
8Site Authentication in Node.js: User Signup
/
-2Creating a Task Manager App Using Ionic: Part 2
/
2Creating a Task Manager App Using Ionic: Part 1
/
1Introduction to Forms in Angular 4: Reactive Forms
/
2
4Introduction to Forms in Angular 4: Template-Driven Forms
/
324 Essential WordPress Utilities to Manage Your Site
/
125 Essential WordPress Utilities to Manage Your Site
/
-8Get Rid of Bugs Quickly Using BugReplay
1 /
-16Manipulating HTML5 Canvas Using Konva: Part 1, Getting Started
/
610 Must-See Easy Digital Downloads Extensions for Your WordPress Site
/
-222 Best WordPress Booking and Reservation Plugins
/
-5Understanding ExpressJS Routing
/
-615 Best WordPress Star Rating Plugins
/
12Creating Your First Angular App: Basics
/
-1Inheritance and Extending Objects With JavaScript
/
-10Introduction to the CSS Grid Layout With Examples
1 /
3
5Performant Animations Using KUTE.js: Part 5, Easing Functions and Attributes
/
-6Performant Animations Using KUTE.js: Part 4, Animating Text
/
-11Performant Animations Using KUTE.js: Part 3, Animating SVG
/
-9New Course: Code a Quiz App With Vue.js
/
-2Performant Animations Using KUTE.js: Part 2, Animating CSS Properties
8Performant Animations Using KUTE.js: Part 1, Getting Started
/
110 Best Responsive HTML5 Sliders for Images and Text (Plus 3 Free Options)
/
-3Single-Page Applications With ngRoute and ngAnimate in AngularJS
/
-14Deferring Tasks in Laravel Using Queues
/
-3
2Site Authentication in Node.js: User Signup and Login
/
10Working With Tables in React, Part Two
/
-17Working With Tables in React, Part One
/
1How to Set Up a Scalable, E-Commerce-Ready WordPress Site Using ClusterCS
/
-2New Course on WordPress Conditional Tags
/
2
-11Building With Vue.js 2 and Firebase
6 /
11
-8
1Best Unique Bootstrap JavaScript Plugins
/
-6
-1Essential JavaScript Libraries and Frameworks You Should Know About
/
5
3Vue.js Crash Course: Create a Simple Blog Using Vue.js
/
-14Build a React App With a Laravel RESTful Back End: Part 1, Laravel 5.5 API
/
2API Authentication With Node.js
/
-4Beginner’s Guide to Angular: HTTP
/
8Beginner’s Guide to Angular: Routing
/
-4Beginners Guide to Angular: Routing
/
-4Beginner’s Guide to Angular: Services
/
2Beginner’s Guide to Angular: Components
/
1How to Create a Custom Authentication Guard in Laravel
/
3Learn Computer Science With JavaScript: Part 3, Loops
/
-3Build Web Applications Using Node.js
/
1Learn Computer Science With JavaScript: Part 4, Functions
/
4Learn Computer Science With JavaScript: Part 2, Conditionals
/
13Learn Computer Science With JavaScript: Part 1, The Basics
/
-1Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts
/
-8Create Interactive Charts Using Plotly.js, Part 4: Bubble and Dot Charts
/
16Create Interactive Charts Using Plotly.js, Part 3: Bar Charts
/
-11Awesome JavaScript Libraries and Frameworks You Should Know About
/
-7Create Interactive Charts Using Plotly.js, Part 2: Line Charts
/
-9Bulk Import a CSV File Into MongoDB Using Mongoose With Node.js
/
-6Build a To-Do API With Node, Express, and MongoDB
/
-8Getting Started With End-to-End Testing in Angular Using Protractor
/
10TypeScript for Beginners, Part 4: Classes
/
-15Object-Oriented Programming With JavaScript
/
410 Best Affiliate WooCommerce Plugins Compared
/
6Stateful vs. Stateless Functional Components in React
/
6Make Your JavaScript Code Robust With Flow
/
-2Build a To-Do API With Node and Restify
/
7Testing Components in Angular Using Jasmine: Part 2, Services
/
3Testing Components in Angular Using Jasmine: Part 1
/
-1Creating a Blogging App Using React, Part 6: Tags
/
-10React Crash Course for Beginners, Part 3
/
4React Crash Course for Beginners, Part 2
/
5React Crash Course for Beginners, Part 1
/
3Set Up a React Environment, Part 4
1 /
9Set Up a React Environment, Part 3
/
-9New Course: Get Started With Phoenix
/
-7Set Up a React Environment, Part 2
/
2Command Line Basics and Useful Tricks With the Terminal
/
8How to Create a Real-Time Feed Using Phoenix and React
/
-4Build a React App With a Laravel RESTful Back End: Part 1, Laravel 9 API
/
-4Creating a Blogging App Using React, Part 5: Profile Page
/
-1Pagination in CodeIgniter: The Complete Guide
/
24JavaScript-Based Animations Using Anime.js, Part 4: Callbacks, Easings, and SVG
JavaScript-Based Animations Using Anime.js, Part 3: Values, Timeline, and Playback
Learn to Code With JavaScript: Part 1, The Basics
/
410 Elegant CSS Pricing Tables for Your Latest Web Project
/
-10Getting Started With the Flux Architecture in React
/
-2Getting Started With Matter.js: The Composites and Composite Modules
/
1Getting Started With Matter.js: The Engine and World Modules
/
1310 More Popular HTML5 Projects for You to Use and Study
/
-19Understand the Basics of Laravel Middleware
/
-1Iterating Fast With Django & Heroku
/
9Creating a Blogging App Using React, Part 4: Update & Delete Posts
/
5Creating a jQuery Plugin for Long Shadow Design
/
-12How to Register & Use Laravel Service Providers
2 /
-13Unit Testing in React: Shallow vs. Static Testing
/
4Creating a Blogging App Using React, Part 3: Add & Display Post
/
13Creating a Blogging App Using React, Part 2: User Sign-Up
20 /
-5Creating a Blogging App Using React, Part 1: User Sign-In
/
59 More Popular HTML5 Projects for You to Use and Study
/
13Creating a Grocery List Manager Using Angular, Part 2: Managing Items
/
89 Elegant CSS Pricing Tables for Your Latest Web Project
/
-4Dynamic Page Templates in WordPress, Part 3
/
-4Angular vs. React: 7 Key Features Compared
/
6Creating a Grocery List Manager Using Angular, Part 1: Add & Display Items
/
2New eBooks Available for Subscribers in June 2017
/
7Create Interactive Charts Using Plotly.js, Part 1: Getting Started
/
10The 5 Best IDEs for WordPress Development (And Why)
/
-233 Popular WordPress User Interface Elements
/
2New Course: How to Hack Your Own App
/
-11How to Install Yii on Windows or a Mac
/
3What Is a JavaScript Operator?
/
-7How to Register and Use Laravel Service Providers
/
9
waly Good blog post. I absolutely love this…