Category Archives: WordPress

WordPress Post Link Not Working

If you've been using WordPress for a good length of time now, you have likely come across a time when you published a post and tried to visit the page and it gave you a 404 not found error, right? Of course I'm right or you probably wouldn't be here reading this, so here are a couple common fixes you should try first when this happens.

Re-Save Permalinks

The first thing I always try is to simply go to wp-admin/settings/Permalinks and make sure the settings are correct and even if they are, save them again just by clicking the button at the bottom of the page even if you do not change a thing! This will often fix your problem, but not always.

Re-Name Your Post and Permalink

Sometimes simply giving your post a new name and changing the Permalink at the top of the page will resolve the problem as well. To do this, simply change the title by adding a word or two and then change the permalink right under the title by changing it to match the new title but make it all small letters and replace spaces with hyphens. One reason this might work is if you had accidentally used a reserved word for your title  or a title that exists for some other purpose in WordPress. When that happens it will simply ignore it and show you a 404 link instead usually. If you do not want to change your posts title, then you can probably get away with just changing the permalink right under the title, but you always have to change the permalink at least to be sure you're not using a reserved word or link that is already in use somewhere else within WordPress.



Basic WP Cron Jobs

This is going to be a simple WP Cron tutorial that explains the basic use of WordPress cron, the wp_schedule_event function and it's 3 built in intervals. I'll write a more complex one soon that explains how to add your own intervals, but this is a good starting point:

Practical Code Example

//Add function to register daily function on WordPress init
add_action( 'init', 'register_daily_cron');

// Function which will register the daily event:
function register_daily_cron() {
    // Make sure event hasn't been scheduled already:
    if(!wp_next_scheduled('daily_cron')) {
        // Schedule the event
        wp_schedule_event(time(), 'daily', 'daily_cron');


Don’t Hard Code WP-Content Directory!

Plugin development tip of the day!
DO NOT HARD CODE wp-content Directory!

I made this mistake not realizing how many people change that directory as a security precaution.


The best alternative is probably the WP_CONTENT_DIR in my opinion. You can also use WP_CONTENT_URL, depending if you want a relative path or a full url.

Here is an example of each followed by the output code:
echo "<br />";
echo "<br />";


So now you know!

Want more? Here are some other ways to get similar paths or directories  from within a plugin file:

echo "<br>";
echo plugins_url( 'myscript.js', __FILE__ );
echo "<br>";
echo plugins_url();
echo "<br>";
echo plugin_dir_url(__FILE__) ;
echo "<br>";
echo plugin_dir_path(__FILE__) ;
echo "<br>";
echo plugin_basename(__FILE__) ;

The above would output the following lines if it were ran from a plugin on



EDD Instant Updater WordPress Plugin

The EDD Instant Updater WordPress plugin is a plugin I created while working with a custom WordPress plugin that needed to have instant update notifications while using Easy Digital Downloads(EDD). EDD comes with it's own updater class, but it uses the default WP standards which means you have to wait up to 12 hours after you push an update to get the notice in the WordPress dashboard! With the EDD Instant Updater plugin, you no longer have to wait, the plugin update notices come to you instantly! No more delays!

Interested? Contact Ian L of by email at for more information.

How to Fix Max File Upload Size on Godaddy and Other Shared hosting Accounts

I ran into this problem using WordPress today where I reached the max upload size on my client's Godaddy server on a shared hosting account. If you get this error in WordPress, while uploading a file, by the way, it's probably a max file size issue:

Error: 1

That's all it said! So it took me a few guesses to figure out what that "Error: 1" message meant.

How to increase the Max File Size Setting in Cpanel

1 - go to your site's Cpanel by going to and log in with the user and password your hosting provider provides for you. You should see this when logged in:


2) scroll down until you see the "Select PHP Version" link in Cpanel that is circled in the below image and click on it:


3) That will take you to the PHP version selection page. Then click the link in the upper right corner of the page that you see circled in the below image:


4) Clicking the "Switch to PHP Options" link in the above image will take you to a PHP settings page. Look for the upload_max_filesize setting that you see circled in the image below and set it to something higher than 2M according to your individual needs:


5) After you change it from "2M" to something higher as needed, click the "Apply" button directly to the right of the dropdown and then be sure to also click the "Save" button near the bottom-left of the page as well and then you are done!

PHP WordPress Large background Importer Code

My wonderful client wanted me to add a .CSV importer that imports posts into a Custom Post Type(CPT) in large quantities of around 10k to 50k at a time.

What a standard WordPress site can handle

From my experience building plugins and importers for WordPress over the past 20 years, I have learned to expect trouble if you try to import anything more than 4k to 5k posts into WP at a time. The main requirement for the importer that I am building now is that it is able to import 20k posts in under 15 minutes. Not too difficult, but a challenge none-the-less because the average WP site will timeout after the first 4k posts on average. I also wanted to accomplish this goal without using any bloated PHP Que libraries or Worker Libraries, so I'll be developing it completely from scratch, just like a grown up!

Step One, Break Large File into Smaller Chunks

The first thing I did while developing my large WP file import feature, was to handle the issue of having a huge .csv file with 20 thousand posts saved in it. What do you do? What I did was wrote a PHP script that reads in that huge file and breaks it up into manageable chunks and saves each chunk to its own separate .csv file. Kind of simple really, this is the easy part!

I created a file named file_split.php to handle this portion of the importer's code. Here are the contents of that file:

$chunk_size = 2000;//size of ea. chunk file given in the no. of lines written to the file(excluding the first line with headings that will be at the top of ea. chunk file created).
$max_files = 0;//it will stop after writing this many files, set to 0 for no limmit
$u = $uploadpath;//"double_accounts-test.csv";
//read a file line by line:
echo "<p>Opening $u to spit it into chunks......</p>";
$file = fopen($u, "r") or exit("Unable to open $u!");
//extract the first line from the file:
$first_line = fgets($file);
//Output a line of the file until the end is reached:
while(!feof($file) &&($iii < $max_files||$max_files==0)) {
$line = fgets($file);
//echo "$i) $line<br>";
//add line to lines that get written to files:
$chunk .= $line;
//once we get to chunk_size lines, write a new file
if($ii == $chunk_size){
//echo "<h3>Chunk #$iii:</h3>";
//echo $chunk;
//create dynamic filenames:
$fn = ABSPATH."wp-content/plugins/YOUR-PLUGIN/temp/chunk$iii.csv";
//echo "Writing file $fn....<br>";
$fh = fopen($fn, 'w') or die("can't open $fn file to overwrite");
fwrite($fh, $chunk);
$m = "<span style='color:green'>Chunk Written to $fn</span><br>";
//reset $ii var back to zero:
$ii = 0;
//empty the $chunk var and add first line to top of file content($chunk)
//echo "<hr><span style='text-align:center;color:orange;font-weight:bold;width:100%;margin-right:111px'>End File #$iii</span>$m<hr>";
echo $m;
//add the file name to the fnames array:
$fnames[] = $fn;
}//end if $ii = $chunk_size
//if $ii is greater than 0 and less then chunk_size, then there was a left over chunk at the end, so write it to a file too:
if($ii > 0 && $ii < $chunk_size){
$noof_files = $iii+1;
$fn = ABSPATH."wp-content/plugins/YOUR-PLUGIN/temp/chunk$noof_files.csv";
echo "Left over chunk of $ii lines remains, so writing it to final file named $fn....<br>";
//echo "Writing Final file $fn....<br>";
$fh = fopen($fn, 'w') or die("can't open $fn file to write final chunk!");
fwrite($fh, $chunk);
echo "<h3 style='color:green'>FINAL Chunk Written to $fn! DONE chunking $u file! Total files created: $noof_files</h3>";
//add final file name to fnames array:
$fnames[] = $fn;
echo "Wow! We broke even with no left over chunk of less than $chunk_size lines, so finished writing files! Final file is $fn.<br>";


Put the file_split.php file up for now. We will include it in another file later when we have the rest of our import feature code written. You can test file_split.php easy enough by

Delete Entire Folder with PHP Code

Today, I had to write a block of pure PHP code to delete an entire folder full of files, sub-folders and more files from a server. This particular job was for a WordPress plugin, but the code I used is not specific to WordPress and can run just fine outside of WordPress or inside a WordPress plugin. The only requirement is an up to date PHP installation for this code to function as intended.


$path = ABSPATH.'wp-content/plugins/cultivate-crm/test';
$dir_arr = parse_dir($path);
global $darr;

function parse_dir($path){
static $cntf = 0;
global $darr;
$d = dir($path);
while (false !== ($entry = $d->read())) {
$filepath = "{$path}/{$entry}";
//Check whether the entry is a file or folder.:
$fof = $entry;
    if($fof != "." && $fof != "..") {
    $fof = $entry;
    $file_type = filetype($filepath);//get file type.
    $file_size = filesize($filepath);//get file size.
    echo "$cntf) $fof<br />Type: $file_type<br />Size: $file_size<hr />";
    if($file_type=='dir'){$darr[]=$filepath;parse_dir($filepath);}else{echo "Deleting $filepath....<br>";unlink($filepath);}
    }//end if is file etc.
}//end while going over files in excel_uploads dir.
}//end parse_dir PHP function by Ian L. of

$c = count($darr);
echo "$c empty directories remain...deleting them now....<br />";
$rdarr = array_reverse($darr);
foreach($rdarr as $dr){
    echo "Folder $dr deleted!<br />";
//and finally remove the test folder:
$test_folder = ABSPATH.'wp-content/plugins/cultivate-crm/test';
echo "Folder $test_folder deleted!<br /><p style='color:green'>Now all temporary folders have been removed from the server!</p>";

Make sure you set your path variable at the top of the script correctly and if you are not in WordPress, replace ABSPATH or set a new PHP constant named ABSPATH and it will work as it is. Since the above code deals with deleting files permanently from the server, I must insist that you use it at your own risk! Be careful because one wrong path entered into this function can destroy your entire file system if you don't know what you are doing!

MailChimp API 3.0 Helper PHP Function

I've been doing a lot of work with the MailChimp API V. 3.0 over the past year while developing the Cultivate CRM WordPress Plugin and I created the following helper function that has made live a lot easier for me since I have to make probably a dozen calls to the API within this one plugin.

MailChimp API 3.0 Helper Function

function mailchimp_request($mcAPIkey,$url,$req_type,$json=''){
//send a HTTP POST, GET or PUT request with curl:
 $ch = curl_init($url);
 curl_setopt($ch, CURLOPT_USERPWD, 'user:' . $mcAPIkey);
 curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($ch, CURLOPT_TIMEOUT, 100);
 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $req_type);//GET, PUT, POST
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 if($req_type!="GET")curl_setopt($ch, CURLOPT_POSTFIELDS, $json);//not needed for GET requests
 $result = curl_exec($ch);
 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 // echo "http code: $httpCode<br />";

$body = json_decode($result);
 //echo "successfully got list for Cultivate CRM!<br />result:<hr />$result<hr />";
 $results['code'] = $httpCode ;
 $results['result'] = $result;
 // store the status message based on response code
 if ($httpCode == 200) {//if no error occurred:
 return $results;
 } else {//else an error occurred:
 return false;
 }//end else an error occurred
 }//end mailchimp_request PHP function by Ian L. of

Calling mailchimp_request Function

Here is how you use the above mailchimp_request PHP function:

//Construct the MailChimp API URL:
$mcAPIkey = 'YOUR-MC-API-KEY';
$mcListID = 'YOUR-MC-LIST-ID';
$memberID = md5(strtolower($email));
$dataCenter = substr($mcAPIkey,strpos($mcAPIkey,'-')+1);
$url = 'https://' . $dataCenter . '' . $mcListID . '/merge-fields/';    
//get the response:
$response = mailchimp_request($mcAPIkey,$url,'GET');
$httpcode = $response['code'];
$result = $response['result'];
$decoded_result = json_decode($result);
echo "http code: $httpcode<br>";
echo "Response data from getting address field data from MC API:
$merged_field_obj = $decoded_result->merge_fields;//should be an array of merged fields

WordPress Plugin Admin Page Unwanted Scroll

I was working on a custom plugin for an important client today and one of the plugin's admin pages would scroll half way down the page every time I landed on it and I couldn't figure out why at first!

Long story short, I found out what was causing it was an inline JavaScript block of code, so If anyone has this issue in a WordPress admin page while making a plugin, try getting rid of the JavaScript and it should stop the page from scrolling as it did in my case.

If you experience something similar, please mention how you solved it in the comments.

How to Count Iterations of a PHP Function

I find myself having to do this all the time! I need to know how many times a function is running and for some strange reason, I almost never remember how to do it correctly. That's why I am posting this simple trick on my blog, so others can find it easily and so I can look at how I did it next time I need to do it again!

Here's a simple example to illustrate the need here:

function runMe(){

$i = 0;


echo "$i<br>";


//If you were to execute the above function in a loop like this:




The output of the above would be:


Not what you wanted? or expected? Often we need it to output something like this instead:


Static Variable to the Rescue

In comes what is know in PHP as Static Variables.  Here's a quick code example that should make you understand how they work:

function countRuns(){

static $c = 0;


echo "$c<br />";


//Then, Executing the countRuns function in a for loop will increment the number printed ea. time:




If you were to run the above tested code in your browser you would get the following output:


That's what I was looking for! okay, so that's how it's done. I hope this helps someone else besides me.



Learning WooCommerce API Manger

What is WooCommerce API Manger?

WooCommerce API Manger is used to secure your software with API License Key activation, deactivation and automatic updates of WordPress plugins and/or themes. However it can also be used for some applications outside of WordPress as well, but we will be talking mostly about how to use it with a custom WordPress plugin.


You need to at least make sure you have at least PHP Version 7.00. Here's how you can check from the linux command line:

php -v

Type the above command and press enter and you should get results that look similar to this:



Alternative Solution to WooCommerce API Manager

You may have noticed this article isn't complete. That is because I decided to go with a different system for selling WordPress plugins on my site with API keys, WooCommerce didn't provide the level of support I needed and their documentation was poor. I discovered Easy Digital Downloads which was much simpler to deploy. Easy Digital Downloads(EDD) in combination with the EDD Software Licensing add-on and the EDD Instant Updater for plugins that I developed myself, became the ultimate solution for selling WordPress plugins outside of If anyone is interested in how I did it, email me at and I can assist you.



How to Keep Custom wp-admin Nav Menu Items Open and Sub-menu Items Highlighted When Clicked

So, I spent a good 3+ hours doing what I thought would be a simple task today. I was working on a custom WordPress plugin named "Cultivate" for a client and made some additions to the admin menu in wp-admin. I added a Main menu item with the plugin name on it and there were 8 sub-menu items under it with links to various admin pages for the plugin.

The Problem

The problem is that the cultivate main menu item should stay open when someone clicks on one of the sub-menu items, but doesn't. So let me demonstrate with a couple of images of the admin area in WordPress. Here's an image of how the admin nav looks just after I clicked on the main menu item "Cultivate". As you can see in the below image, the Cultivate menu is open and you can see the 8 submenu items below it. When it is closed all you see if the "Cultivate" menu item, but here it is open:


Okay, that's all good and fine. You can see the sub-menu items and you can see "Cultivate" main menu item is highlighted because that page is now open. So, everything looks great! However, below is another image of how it looks after clicking on one of the sub-menu links below the "Cultivate" main menu item. In the next image, I have just clicked on the "Pods" sub-menu item under "Cultivate":


Now do you see the problem? Not only is the main "Cultivate" menu item closed, but the "Pods" sub-menu item isn't even present. Pods should be visible and highlighted which is not possible without the sub-menu being opened! So, after hours of research and coding, I finally figured out how to make this custom wp-admin menu work as it should. Here is how it looks after clicking on "Pods" under "Cultivate" after I added my code which I'll show you shortly:


See how in the above image, the main "Cultivate" menu remained open and the "Pods" sub-menu item is highlighted after going to the custom admin page?  That's how it should work! That's how it works after adding my custom PHP and jQuery code shown below.

The Solution

The solution is a block of PHP code added to your plugin file or functions.php file and a custom jQuery script for each sub-menu item. It might sound like a lot to make a separate .js file for each sub-menu item, but you only have to change one word in each file, so not a huge deal really.

The PHP Code

Here's the PHP code you can add to your main plugin file or to functions.php if you're adding it to a theme:

First we will just add the following PHP code, then below that you can see the complete script, but you'll want to run this partial script first to get your page names for the if statements to function properly:

add_action('admin_head', 'jafty_set_open_menu');
//Open the correct menu for taxonomy
function jafty_set_open_menu(){
    $screen = get_current_screen();
    $screenname = $screen->base;
    $screentax = $screen->taxonomy;
    $posttype = $screen->post_type;
    //uncomment next line to write name of page, post type and taxonomy to log:
    log_debug("\n\nOpened page: $screenname\nOpened Taxonomy: $screentax\nPost Type: $posttype\n\n");

}//end jafty_set_open_menu function by Ian L. of

//Custom function to write data to log file:
function log_debug($log){
    $pdir = plugin_dir_path( __FILE__ );//gets the directory of current file with trailing slash whether inside plugin or not!
    $myFile = $pdir."my_log.txt";
    $fh2 = fopen($myFile, 'a') or die("can't open file to append");
    fwrite($fh2, $log);
}//End log_debug PHP function

Now with the above code installed in your main plugin file or functions.php file, you'll also need to add a file to your plugin's main directory named my_log.txt and give it write permissions. This way it will write the page names and any possible taxonomy or post types you need to insert later in the script to the log file when you click on the admin nav links. So you click on a sub link, then see what was written to the log file. Repeat for ea. sub link. and write down the values written to the log file. Then you use what you wrote down to plan your PHP if statements correctly according to the page, post type and taxonomies used.

With that said, here's the entire script that worked for my Main menu item with 8 sub menu items below it"

//code to keep main menu open if submenu items are clicked:
add_action('admin_head', 'jafty_set_open_menu');
//Open the correct menu for taxonomy
function jafty_set_open_menu(){
    $screen = get_current_screen();
    $screenname = $screen->base;
    $screentax = $screen->taxonomy;
    $posttype = $screen->post_type;
    //comment out next line to stop writing the page and taxonomy names to log file:
    log_debug("\n\nOpened page: $screenname\nOpened Taxonomy: $screentax\nPost Type: $posttype\n");
    //next will be a separate block of code for ea. submenu item in the main menu to trigger the proper .js file to manipulate the nav menu properly for ea.:
    //code for the "People" submenu item:
    if($screenname === 'edit' && $posttype === 'people'){
        wp_enqueue_script( 'open-menu-parent_people', plugins_url('js/open_admin_menu_people.js', __FILE__ ), array('jquery') );
    //code for the "Pods" submenu item:
    if($screenname === 'edit-tags' && $screentax === 'pods'){
        wp_enqueue_script( 'open-menu-parent_pod', plugins_url('js/open_admin_menu_pod.js', __FILE__ ), array('jquery') );
    //code for the "Touchpoints" submenu item:
    if($screenname === 'edit' && $posttype === 'touchpoints'){
        wp_enqueue_script( 'open-menu-parent_touchpoints', plugins_url('js/open_admin_menu_touchpoints.js', __FILE__ ), array('jquery') );
    //code for the "Campaigns" submenu item:
    if($screenname === 'edit-tags' && $screentax === 'campaigns'){
        wp_enqueue_script( 'open-menu-parent_campaigns', plugins_url('js/open_admin_menu_campaigns.js', __FILE__ ), array('jquery') );
    //code for "Forms" submenu item:
    if($screenname === 'cultivate_page_forms_admin_pg'){
        wp_enqueue_script( 'open-menu-parent_forms', plugins_url('js/open_admin_menu_forms.js', __FILE__ ), array('jquery') );
    //code for "Custom Fields" submenu item:
    if($screenname === 'cultivate_page_custom_fields_admin_pg'){
        wp_enqueue_script( 'open-menu-parent_custom_fields', plugins_url('js/open_admin_menu_custom_fields.js', __FILE__ ), array('jquery') );
    //code for "MailChimp Admin" submenu item:
    if($screenname === 'cultivate_page_mailchimp_admin_pg'){
        wp_enqueue_script( 'open-menu-parent_mailchimp_admin', plugins_url('js/open_admin_menu_mailchimp_admin.js', __FILE__ ), array('jquery') );
}//end jafty_set_open_menu function by Ian L. of

Now the jQuery Code:

You'll need one .js file with the following contents for each sub-menu item you have in your admin nav. All you have to change in the text that reads "MailChimp Admin" in my example below to the link text of the sub-menu item for ea. separate .js file you use:

(function($) {
    // Close all the other parent menus

    // Open your specific parent menu
    $('.toplevel_page_cultivate_settings_pg')//set to menu name for cultivate menu
        .addClass('wp-has-current-submenu wp-menu-open');

            $('.toplevel_page_cultivate_settings_pg .wp-submenu-wrap').find('li').each(function(){
                 var current = $(this);
                    if(current.text()=='MailChimp Admin'){



Nice huh? It took me forever to get this to work, but with the above code you should be able to do it in minutes.

WordPress Custom Post Type Meta Box with Form Validation

So I'm going to cover a lot in a little time in this tutorial so pay close attention and you'll learn fast I hope.


What You'll Learn

  • How to create a simple WordPress plugin
  • How to create a custom post type in WordPress
  • How to add custom fields to a custom post type
  • How to add meta boxes to wp-admin
  • How to save custom post type's custom fields
  • How to handle form validation for custom meta boxes
  • How to display errors in wp-admin

So while it might seem like a lot to cover, I will demonstrate all of the above points with a simple WordPress plugin that adds a custom post type to WordPress and validates the user's input.

Here are the steps you'll follow:

  1. Start a new plugin
  2. Add a new custom post type
  3. Add meta boxes to a custom post type
  4. Add WordPress Error Handler Functions
  5. Write PHP Function to Save Custom Fields Data Meta Boxes

Step One - Start a new plugin

Create a folder on your desktop, pick a name for your plugin and name the folder accordingly. Lets say for the purpose of making this tutorial, we'll name our plugin "Cars" so we created a folder named "cars" on our desktop. Then add a php file named cars.php and make enter the proper comments at the top of the cars.php file so WordPress will recognize your new plugin. Here's how I did it:

 * Plugin Name: Cars
 * Plugin URI:
 * Description: A custom Car plugin developed for WordPress car websites.
 * Version: 0.0.1
 * Author: Ian L. of
 * Author URI:
 * License: GPL2


Feel free to change the name , Plugin URI, Description, etc to fit your desires.

Step Two - Add a Custom Post Type

Next we need to add code to cars.php that will create a new Custom Post Type or CPT in wordpress. Here's example code to create the cars CPT:

//Add cars Custom Post Type:
add_action('init', 'create_cars_cpt');
function create_cars_cpt() {
    $labels = array(    
      'name' => _x( 'cars', 'cars' ),
      'singular_name' => _x( 'car', 'cars' ),
      'add_new' => _x( 'Add New car', 'cars' ),
      'add_new_item' => _x( 'Add New car', 'cars' ),
      'edit_item' => _x( 'Edit car', 'cars' ),
      'new_item' => _x( 'New car', 'cars' ),
      'view_item' => _x( 'View car', 'cars' ),
      'search_items' => _x( 'Search cars', 'cars' ),
      'not_found' => _x( 'No cars found', 'cars' ),
      'not_found_in_trash' => _x( 'No cars found in Trash', 'cars' ),
      'parent_item_colon' => _x( 'Parent car:', 'cars' ),
      'menu_name' => _x( 'cars', 'cars' ),
 $args = array(
      'labels' => $labels,
      'hierarchical' => false,
      'description' => 'cars',
      'supports' => array( 'title', 'author' ),//author adds the author metabox to cars CPT add car/edit car screens.
      'public' => true,
      'show_ui' => true,
      'show_in_menu' => true,
      'show_in_nav_menus' => true,
      'publicly_queryable' => true,
      'exclude_from_search' => false,
      'has_archive' => true,
      'query_var' => true,
      'can_export' => true,
      'rewrite' => array('slug' => 'car'),
      'map_meta_cap'  => true,

    register_post_type( 'cars', $args );
}//end create_cars_cpt function

Simply add the above code in green to your cars.php file after the comment area but before then closing PHP tag and save the file.

Step Three - Add simple Meta Box to Our Plugin

Here is my code for reference which you may copy, paste and change as needed:

//Add the Cars Meta Boxes:
add_action( 'add_meta_boxes', 'add_cars_metaboxes' );
function add_cars_metaboxes() {
add_meta_box('create_car_metabox', 'Car Information', 'create_car_metabox', 'cars', 'normal', 'high');
//############################## Function to create the meta box: ########################
function create_car_metabox($p='') {
global $post;
// Noncename needed to verify where the data originated
echo '<input type="hidden" name="eventmeta_noncename" id="eventmeta_noncename" value="' .
wp_create_nonce(plugin_basename(__FILE__)) . '" />';

$car_year = get_post_meta($p, '_car_year', true);
$car_make = get_post_meta($p, '_car_make_time', true);
$car_model = get_post_meta($p, '_car_model_time', true);

//get post meta for car:
$car_year = get_post_meta($post->ID, '_car_year', true);
$car_make = get_post_meta($post->ID, '_car_make_time', true);
$car_model = get_post_meta($post->ID, '_car_model_time', true);
}//end if post ID is set

//add HTML for meta box form fields:
<div style="float:left">
<span class='field-head'>Car Year:</span> <select name="car_year">
<option value="none">Select Year</option>
<option value="1990"<?php if($car_year=="1990")echo " selected";?>>1990</option>
<option value="1991"<?php if($car_year=="1991")echo " selected";?>>1991</option>
<option value="1992"<?php if($car_year=="1992")echo " selected";?>>1992</option>

<div style="float:left">
<span class='field-head'>Car Make:</span> <select name="car_make">
<option value="none">Select Make</option>
<option value="Ford"<?php if($car_make=="Ford")echo " selected";?>>Ford</option>
<option value="Chevy"<?php if($car_make=="Chevy")echo " selected";?>>Chevy</option>
<option value="Dodge"<?php if($car_make=="Dodge")echo " selected";?>>Dodge</option>

<div style="float:left">
<span class='field-head'>Car Model:</span> <select name="car_model">
<option value="none">Select Model</option>
<option value="1990"<?php if($car_model=="1990")echo " selected";?>>1990</option>
<option value="1991"<?php if($car_model=="1991")echo " selected";?>>1991</option>
<option value="1992"<?php if($car_model=="1992")echo " selected";?>>1992</option>

}//end create_car_metabox function to create car tabs

Paste the above code in your cars.php file right after the last line of PHP code but before the closing PHP tag.

Step Four - Add Error Handling Functions to Your Plugin:

Now we need a couple quick functions to handle errors later on, so copy and paste the following code into your cars.php file next just after the last code you added from step three above:

//Next we need two simple error handling functions:
//Error handling function for use with save_car_data function below it:
add_action('admin_notices', 'handle_car_errors');
 * Writes an error message to the screen if error is thrown in save_car_data function
function handle_car_errors() {
  //If there are no errors, then exit the function
  if(!( $errors = get_transient('settings_errors'))) {
  //Otherwise, build the list of errors that exist in the settings errors
  $message = '<div id="acme-message" class="error below-h2"><p><ul>';
  foreach($errors as $error) {
    $message .= '<li>' . $error['message'] . '</li>';
  $message .= '</ul></p></div><!-- #error -->';
  //Write error messages to the screen
  echo $message;
  //Clear and the transient and unhook any other notices so we don't see duplicate messages
  remove_action('admin_notices', 'handle_car_errors');

function car_error($slug,$err){
    set_transient('settings_errors', get_settings_errors(), 30);
}//end car_error function by Ian L. of

Step Five - Save Meta Box Data in WordPress

Now that we have our error handling functions ready, we can write in our function to save the data. You can copy and paste my save_car_data function and it's action hook as follows:

//############### SAVE ALL ABOVE METADATA FROM META BOXES HERE: ##################
//hook to save the meta box data:
//add_action('save_post', 'save_touchpoint_data');
add_action('save_post_cars', 'save_car_data');
function save_car_data($post_id) {
    //get the car post's title title and verify it first:
    $ti = get_the_title($post_id);
    //if the title is blank, throw an error:
    if($ti=='')car_error('title_missing','Oops! You forgot to enter a title. Please enter a valid car title and click the update button.');

    //save the car's year:
    //first make sure they picked a year:
    $y = $_POST['car_year'];
    if($y == 'none'){
        car_error('missing_car_year','Opps! You have not selected a year for the car. Please select a year and click the update button to save it afterwards.');
    update_post_meta($post_id, '_car_year', strip_tags($y));
    //save the car's make:
    //first make sure they picked a make:
    $y = $_POST['car_make'];
    if($y == 'none'){
        car_error('missing_car_make','Opps! You have not selected a make for the car. Please select a make and click the update button to save it afterwards.');
    update_post_meta($post_id, '_car_make', strip_tags($y));
    //save the car's model:
    //first make sure they picked a model:
    $y = $_POST['car_model'];
    if($y == 'none'){
        car_error('missing_car_model','Opps! You have not selected a model for the car. Please select a model and click the update button to save it afterwards.');
    update_post_meta($post_id, '_car_model', strip_tags($y));
}//end save_car_data function

That's all there is to it! Copy and paste the above code into your cars.php file just before the closing PHP tag and save the file, then upload the entire cars folder to your site's plugins directory and navigate to wp-admin and click on "plugins" then find your new plugin and click "activate" to activate it and you will see the new custom post type, "Cars" appear in the main wp-admin nav that runs down the left side of the page.

Screen Shots:

Here is what it will look like if you just try to click on "Publish" when adding a new car without entering any values into the add new car page at all:


Below is what the add new Car screen looks like:



There you have it! A simple plugin with everything you need to get you started creating your own custom post types in WordPress that include custom fields, meta boxes and even error handling code! A WordPress beginner's dream! Good Luck with your next theme or plugin!

Sorting Multi-Dimensional Associative Arrays in PHP

Learning  how to sort a multi-dimensional associative array in PHP was a bit difficult for me to figure out, so I hope documenting it here will help others figure it out a little faster.

In many cases, sorting multi-dimensional arrays is used to sort data retrieved from a database. For this exercise, let's say we have the following database structure:


The above image is from a database I was working on for a client while building a custom WordPress plugin in PHP. I needed to present the data from the table in order according to two fields, "term" and "qty". The task in my case was extra difficult because it also had to be sorted with a custom function. First we will do a simple sort with built in functions and then I'll explain how I solved my custom sorting issue.

Fetching Data From WordPress Database to Build an Associative Array

I was building a WordPress plugin when I encountered the need for this code, so that is what I'm using as an example, but the code is basically the same if you do it outside of WordPress also. The only difference would be how you do the database query. I am leaving the WordPress code in tact in case some of my readers could benefit from it. We have to build the array first. I'll provide test code below to build an array without having to query the database for those of you who may need it.  Here is the PHP code I wrote to fetch data from a custom table in WordPress

global $wpdb;
$table_name = $wpdb->prefix . 'table_name';
$where_clause = "WHERE campaign='$t_name'";
$query="SELECT * FROM $table_name $where_clause";
$results = $wpdb->get_results($query);
$rowcount = $wpdb->num_rows;
echo "<p>Rows Found: $rowcount</p>";
if($rowcount > 0){//only continue if there are rows found!
    foreach($results as $r){
        $db_id = $r->id;
        $stp = $r->touchpoint;//saved touchpoint name will be same as $tp
        //get type, qty, term, relative_to and date:
        $typ = $r->type;
        $qty = $r->qty;
        $trm = $r->term;
        $rel_to = $r->relative_to;
        $dat = $r->date;
        //add ea. of the 5 values and an associative array for ordering later on:
        //build an associative multi_dimensional Array of data:
        $assoc_array[$stp]['type'] = $typ;
        $assoc_array[$stp]['qty'] = $qty;
        $assoc_array[$stp]['term'] = $trm;
        $assoc_array[$stp]['order'] = $order;
        $assoc_array[$stp]['relto'] = $rel_to;
        $assoc_array[$stp]['date'] = $dat;
    }//and foreach result
}//end if there were rows of data found

Building a Multi-Dimensional Associative Array in PHP

For those of you not interested in the WordPress part of this exercise, I've also included another way to build the same associative multi-dimensional array in simple PHP code below:

$assoc_array["call owner"] = Array
"type" => "Relative",
"qty" => 2,
"term" => "hours",
"order" => "a",
"relto" => "last",
"date" => "none"

$assoc_array["email tommorow"] = Array
"type" => "Relative",
"qty" => 1,
"term" => "days",
"order" => "b",
"relto" => "last",
"date" => "none"

$assoc_array["yearly touchpoint"] = Array
"type" => "Relative",
"qty" => 1,
"term" => "years",
"order" => "e",
"relto" => "last",
"date" => "none"

$assoc_array["Welcome Email"] = Array
"type" => "Relative",
"qty" => 1,
"term" => "hours",
"order" => "a",
"relto" => "last",
"date" => "none"

Sorting an Associative Multi-Dimensional Array by Two Keys or Values

We can use the PHP function, array_multisort, to sort multi-dimensional arrays by two fields as follows:


//Make a $tempArr of sort columns and their data to pass to array_multisort function  
    $tempArr = array();

    foreach($assoc_array as $key=>$val) {
        $tempArr['order'][$key] = $val['order'];
        $tempArr['qty'][$key] = $val['qty'];
// sort by order asc and then qty asc
    array_multisort($tempArr['order'], SORT_ASC, $tempArr['qty'], SORT_ASC,$assoc_array);


Sum It Up!

This was a relatively short ans sweet tutorial on PHP arrays as far as such things often go. There is however a lot more to learn when it comes to working with arrays in PHP. To see all of the PHP array related functions in one place, check out this link:

Developer’s Guide to Working With Contact Form 7

Today, I had the unfortunate pleasure of working with Contact Form 7. I must admit that it was a little refreshing to see such an under-developed WordPress plugin for a change. I've gotten used to the over-developed monstrosities of today, but CF7 is truly bare-bones when it comes to functionality. It does on basic task and, I assume, does it well, since its such a popular WordPress plugin today. Contact Form 7 allows you to set up a contact form on your website that will email specific information you set up in the form to collect. It is supposed to be simple and sometimes it is. If it works the first time out of the box, you're one of the lucky ones. I had issues. The issues I had were not necessarily the plugin's fault, however, they could have saved me some time with more complete documentation regarding what to do when it fails. My issue ended up being that PHP mail function wasn't functioning, so I downloaded an SMTP plugin to resolve the issue before continuing to develop the code in this guide.

How to retrieve information submitted in Contact Form 7 Forms

The goal of this guide is to teach you how to retrieve data submitted in CF7 forms and work with it in a plugin or from your functions.php file if you prefer it that way.

Why Retrieve Data from Contact Form 7 Forms?

There are a lot of good answers to this question, but it basically depends on your individual needs and desires. The best answer perhaps is to save the form data in a database or log file because CF7 doesn't store any data from form submissions! I've heard there are plugins or add-ons for CF7 that enable CF7 to store it's data in a database, but for the sake of learning how to retrieve data, we won't be using one of those plugins today. Actually, we won't even store the info in a database. Everybody should know how to do that if they are advanced enough to be attempting this guide, so we will save form data to a log file instead, just because, as far as I know, there is no guide available that tells you how to do that as of the time I am writing this guide.

Okay that's enough on why, you can think of your own reason why....let's get to the how!

Retrieving Data From CF7 Forms

The first thing we need to accomplish is to hook into the form when it is submitted somehow. I've found that the action hook named "wpcf7_before_send_mail" works great for this purpose. Here is how to use wpcf7_before_send_mail:

add_action( 'wpcf7_before_send_mail', 'process_contact_form_data' );
function process_contact_form_data( $contact_form ){


...that is your basic action and call back function set up. Now all we need is to add some code inside of the empty process_contact_form_data function. We need to gather data submitted in the Contact Form 7 form, so let's look at how we can do that, shall we?

An integral class used in retrieving form data since CF7 Version 3.9 is known as the "WPCF7_Submission" class which includes the "get_instance()" method used to fetch data arrays. To be complete you should check for the class and then use get_instance() to fetch the data like this:

function process_contact_form_data( $contact_form ){

if (!isset($contact_form->posted_data) && class_exists('WPCF7_Submission')) {
    $log .= "posted data set and class exists!\n";
        $submission = WPCF7_Submission::get_instance();
        if ($submission) {
            $log .= "submission exists!\n";
            $formdata = $submission->get_posted_data();

}//end process_contact_form_data function

What the above code does is puts the posted form data into an array named $formdata. To get a specific form field's data you need to use the field's name attribute as a key to the $formdata array. For example, if you used the default CF7 form setup, you would access the submitted name, email, subject and message like this:

$name = $formdata['your-name'];

$email= $formdata['your-email'];

$subj = $formdata['your-subject'];

$name = $formdata['your-message'];

The above code would go inside the above function just before the closing bracket, then you'll need code to write those variables to a log file as we discussed earlier. The basic code to write to a file from PHP looks like this:

$myFile = "/complete/path/cf7_log.txt";
$fh2 = fopen($myFile, 'a') or die("can't open file to append");
$stringData = "form ID: $form_id\n name:$name\n email: $email\n $log\n\n";
fwrite($fh2, $stringData);

Okay! Now we just have to put all the pieces together inside the process_contact_form_data PHP function inside of your plugin file or functions.php file. To keep things safe, I suggest making your own little plugin for this, so that's what I'll do next, create a single file plugin that simply writes CF7 form data to a log file inside the plugin's main folder. Let's call our plugin CF7_logger.

You can easily make the plugin described by piecing together the code snippets in this guide, or you can purchase the entire tested and debugged version from me by emailing Good Luck!


WordPress Permalinks Not Working

I had this issue today after migrating a WordPress website to a new server using backupbuddy and wanted to post the quick solution here in case it might help anyone else as it did me. It can sometimes take hours to solve simple problems like this. This fix applies to apache2 servers that won't work with WordPress permalinks when they are set to something like "Post Name" as mine were. I'll post two simple solutions that will fix most situations when this happens:

Save Permalinks

The first thing you want to try is simply going to wp-admin and clicking on "settings/permalink" and selecting the correct setting if not selected already and clicking the "Save Settings" button to re-save the settings(even if they were correct), Then refresh the page where links failed before and try them again. If that didn't work and you are on a Apache or Apache2 server, move on to the next fix below.

Edit Config File

Next try going to etc/sites-available and find the file named after your site which will look something like and open it for editing either using VI editor from command line or by downloading to your desktop and editing with note pad. My file that failed to work had the following content:

<Directory /var/www/html/>
    Require all granted
<VirtualHost *:80>

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/

    ErrorLog /var/www/html/
    CustomLog /var/www/html/ combined

The problem was right up at the top where you see the line:

      Require all granted

I simply added the following two lines above that one line and saved it to my server then restarted the server from command prompt with:"service apache2 restart" and the permalinks began working! Here are the two lines to add above "Require all granted":

        Options Indexes FollowSymLinks MultiViews
        AllowOverride All

Then simply save the file and restart your server and try permalinks again and they should work! The final .conf file should look like this:

<Directory /var/www/html/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
<VirtualHost *:80>

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/

    ErrorLog /var/www/html/
    CustomLog /var/www/html/ combined

Hope that helps! Good Luck!


Get Current Plugin’s URL with and without a Trailing Slash

This quick WordPress tutorial will demonstrate how to get the plugin folder path to your plugin from within a plugin file. We are building a plugin named WP-PW-sync in our examples and the code in question will be inside a the main plugin file named WP-PW-sync.php, but could be in any file within the plugin's folder(WP-PW-sync folder). I will  demonstrate two methods for getting the current plugin's directory path, one that includes a trailing slash at the end of the URL and one that does not.

NOTE: if you want a path instead of a URL(/var/www/ instead of, then skip down about half way down this page to the section regarding paths instead of URLs.

How to Get Plugin URL Without a Trailing Slash

To get the current plugin's url without a trailing slash, I often use the plugins_url WordPress function like this:

$pluginURL1 = plugins_url('',__FILE__);//this plugin's URL without trailing slash

So, if I then typed "echo $pluginURL1;", it would output something like:

Note that the plugins_url function takes two parameters and is typically used for other uses when using the first parameter as I will explain below.

plugins_url parameters:

plugins_url($path, $plugin);

(string) (optional) Path to the plugin file of which URL you want to retrieve, relative to the plugins or mu-plugins directory or to $plugin if specified.

Default: None
(string) (optional) Path under the plugins or mu-plugins directory of which parent directory you want the $path to be relative to.

Default: None

How to Get Plugin URL Including the Trailing Slash

To get the current plugin's URL with a trailing slash at the end, I typically use the plugin_dir_url WordPress function like so:

$pluginURL2 = plugin_dir_url(__FILE__);//this plugin's URL with trailing slash

Then if I were to type "echo $pluginURL2;" it would output something similar to this:

plugin_dir_url Parameters:

The plugin_dir_url WordPress function only has one parameter:


(string) (required) The filename of the plugin (__FILE__)

Default: None

Notice the / at the end of the URL, that's the only difference in the two examples above.

Next we'll go over how to get a path instead of a URL!

How to Get the Current Plugin's Path with Trailing Slash

Okay, maybe you don't want a URL, but a path like "/var/www/ instead. If so, you're in the right part of the tutorial! Here's how to get your current plugin's path including a trailing slash at the end from within the main plugin file, WP-PW-sync/WP-PW-sync.php(in out example case):

$pluginPATH = plugin_dir_path( __FILE__ );//this is the plugin's PATH with a trailing slash at end

If you were to add "echo $pluginPATH;" to your script, it would output something similar to this:


plugin_dir_path function  parameters

The plugin_dir_path function only takes a single parameter, $file:;



(string) (Required) The filename of the plugin (__FILE__).

How to Get a Plugin's Path Without the Trailing Slash

Unlike at the top of this tutorial, when we were working with complete URLs, there is not a separate WordPress function for with and without the trailing slash, so I like to incorporate the use of the untrailingslashit function to get the path without the slash at the end like so:

$pluginPATH = plugin_dir_path( __FILE__ );//this is the plugin's PATH with a trailing slash at end
$pluginPATH2 = untrailingslashit($pluginPATH);//this is the plugin's path without the trailing slash

Now if we were to add "echo $pluginPATH2;" to our script, it would out something like this:


Notice that there is no longer a slash at the end of the output in the above case.

It is also noteworthy that the untrailingslashit function can be used to remove a slash from the end of any string, so it has many other uses other than simply removing the slash from the end of the plugin's directory path as we have done here. HAPPY CODING!



How to Create a WordPress Child Theme

In this tutorial we will learn a simple step by step process for creating a WordPress child theme.

Why make a child theme?

The answer is simple. We make a child theme in so we don't mess up the main theme. Also when WordPress decides it is time to update your theme, you won't loose all of your custom code because it will be protected inside your own child theme which isn't effected by parent theme updates!

Tools you will need:

  1. FileZilla or another FTP application running on your desktop.
  2. Notepad++, Notepad or another plain text editor.

Step by Step Instructions for Making a WordPress Child Theme

  1. Name your child theme by appending "-child" to the name of it's parent theme. In this example, we will make a child theme for the twentyseventeen theme, so we will name it "twentyseventeen-child". To lock in the name, create a new folder on your desktop(right-click on desktop and select new/folder in Windows) and name it "twentyseventeen-child".
  2. Using your text editor application, create a new file in the folder you created on your desktop in step one and name it style.css. Then copy and paste the code below under the "Style Sheet Code" heading into the twentyseventeen-child/style.css file and save it. When doing so, make sure the template: setting is set to the directory name of the parent theme.
  3. Create a second file in your twentyseventeen-child folder on your desktop named "functions.php" and copy and paste the code below under the "Functions.php Code" heading. Save it.
  4. Upload the twentyseventeen-child folder to your site's wp-content/themes directory, activate it and check several pages of your site to make certain everything looks the same as it used to as we have not made any changes yet. See the section below entitled "Troubleshooting" if it doesn't look exactly like the parent theme at this point or if you have any other issues.
  5. Once you have a working child theme identical to it's parent, start modifying it! You can over-ride any file of the parent theme by including it in the child theme's folder and altering the code.


Style Sheet Code

 Theme Name:   Twenty Seventeen Child
 Theme URI:
 Description:  Twenty Seventeen Child Theme
 Author:       Ian L. of
 Author URI:
 Template:     twentyseventeen
 Version:      1.0.0
 License:      GNU General Public License v2 or later
 License URI:
 Tags:         light, dark, two-columns, right-sidebar, responsive-layout, accessibility-ready
 Text Domain:  twenty-seventeen-child

Functions.php Code

function my_theme_enqueue_styles() {

    $parent_style = 'twentyseventeen-style'; // This needs to be set to the value from the parent theme's wp_enqueue_style line in the parent functions.php file

    wp_enqueue_style( $parent_style, get_template_directory_uri() . '/style.css' );
    wp_enqueue_style( 'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( $parent_style ),
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );


  • Styles do not match that of parent site before making style changes. If you have this issue then it is likely that your parent theme didn't include all of it's styles inside of the standard style.css file. Look in the parent theme's functions.php file and search for "wp_enqueue_style" and carefully include any other enqueued styles besides style.css into your child theme's functions.php as well. If you copy the lines from parent to child, be certain you change "get_stylesheet_directory_uri" to "get_template_directory_uri" and it should work fine.
  • Some pics don't show up in child theme that showed up in parent theme. If this happens, re-enable the parent theme and find the images that were not working and make a note of their URL(right click on image and click view image). The images that were not working are likely to have been included inside the parent theme, so duplicate their path inside the child theme and make a copy of the images there. For example, if the images were in twentyseventeen/assets/media/pics in the parent theme, then create those folders in the child theme like twentyseventeen-child/assets/media/pics and copy the images there as well. That's the easy way. If you want more of a challenge and don't want to cpy the images, find and edit the path in the code for ea. image that is not displaying.

Understanding ARIA Click Button to Show or Hide Content Example Code

Understanding ARIA

ARIA stands for "Accessible Rich Internet Applications". Also known as the WAI-ARIA standard, it is a standard developed to help coders to provide proper semantics for custom widgets and to make them accessible, usable, and interoperable with assistive technologies for people with disabilities. To be clear, ARIA doesn't add functionality to an object. It adds roles and states that assist in identifying the intent and state of an object. However, usually JavaScript code is still needed to add any dynamic action to that object. I state this clearly at the top of this post because at first, I was under the impression that ARIA also added certain functionalities to HTML objects and was seriously disappointed when I found out otherwise. For example, when ARIA is used on a button that hides and shows content in a div, it only defines the roles and states of the button and corresponding div. JavaScript is still needed to do that work of hiding and showing the div in question.

Example Code

Here is an example of correctly implementing ARIA controls when making a button that hides and shows a div on the click of your mouse. It also binds the space bar and enter key to the div as well, so pressing either of those keys toggles the visibility of the div as well. Without any further ado, the code:

<!DOCTYPE html>
<meta charset="UTF-8" />
<title>Aria Examples</title>
<script src=""></script>

div.topic {
    display: none;
    margin-bottom: 1em;
    padding: .25em;
    border: black thin solid;
    background-color: #EEEEFF;
    width: 40em;

<p class="button">
    <button id="button1" class="buttonControl" aria-controls="t1" aria-expanded="false"><span>Show</span> Topic 1</button>

<div id="t1" class="topic" role="region" tabindex="-1" >
    Topic 1 is all about being Topic 1 and may or may not have anything to do with other topics.

$(document).ready(function() {

   var hs1 = new hideShow('button1');
  // var hs2 = new hideShow('button2');
  // var hs3 = new hideShow('button3');
  // var hs4 = new hideShow('button4');
}); // end ready()

// function hideShow() is the constructor for a hideShow widget. it accepts the html ID of
// an element to attach to.
// @param(id string) id is the html ID of the element to attach to
// @return N/A
function hideShow(id) {

   this.$id = $('#' + id);
   this.$region = $('#' + this.$id.attr('aria-controls'));

   this.keys = {
               enter: 13,
               space: 32

   this.toggleSpeed = 100;

   // bind handlers

} // end hidShow() constructor

// Function bindHandlers() is a member function to bind event handlers to the hideShow region
// return N/A
hideShow.prototype.bindHandlers = function() {

   var thisObj = this;

   this.$ {


      return false;

// Function toggleRegion() is a member function to toggle the display of the hideShow region
// return N/A
hideShow.prototype.toggleRegion = function() {

      var thisObj = this;

    // toggle the region
    this.$region.slideToggle(this.toggleSpeed, function() {

      if ($(this).attr('aria-expanded') == 'false') { // region is collapsed

        // update the aria-expanded attribute of the region
        $(this).attr('aria-expanded', 'true');

        // move focus to the region

        // update the button label

      else { // region is expanded

        // update the aria-expanded attribute of the region
        $(this).attr('aria-expanded', 'false');

        // update the button label

} // end toggleRegion()

Thank you for providing me with enough knowledge to create and use the above example! They have the best example code for ARIA usage that I could find online after many Google searches. See their complete list of example ARIA examples at

ARIA and WordPress

I noticed ARIA controls for the first time in the header.php file for my WordPress theme. I was trying to fix a mobile navigation menu and thought couldn't find the code that makes the menu appear on mobile devices when the button is clicked and thought ARIA had something to do with it. I was basically wrong. ARIA code was only present to mark the navigation menu and make it's role and states readily accessible. It is after all an accessibility feature.


So ARIA and the WAI-ARIA standard are used to enable more accessible HTML markup for disabled people. While it is a great initiative, it doesn't add much dynamic functionality to your HTML objects, JavaScript is still needed for that. ARIA combined with HTML, CSS and JavaScript can be used to make accessible web pages more user-friendly.

How to Add Custom Fields to WordPress Navigation Menu Items

The task of adding custom fields to WordPress navigation menus has come up a few times in my work, so I figured I should document the process which I have learned since it is fairly complex and not very well documented on the internet to this date. Kudos to those of you who have figured this out and documented it because it is one of the more advanced tasks involving WordPress that I have had to do. I am not sure why WordPress made it so complex to alter the navigation menu infrastructure, but to be a true WordPress expert, you do need to learn to work with it, so I aim to help others learn, as I have, how to manipulate the WordPress navigation menus with as much ease as possible.

This is by far one of the more advanced tutorials for WordPress, so if you don't feel like going through all of the steps below. I've already made a plugin for this that will be for sale on my site. If you want to get an advance copy of it email me at and I can help you out.

Adding custom Fields to WordPress Navigation Menu Items

To be perfectly clear, here is a screenshot of the default menu editing screen after I made my initial top navigation menu for my site, with no added custom fields:


In contrast, here is the same screen under appearance/menus after I have added two custom fields to it using the methods I'll describe below:


Notice in the above image, the addition of the "Icon URL" and "Custom Field #2" fields. These I added with my custom plugin. Read on to find out how to add similar fields and how to access them or display them on the front-end of your site.

On the front-end, I added two icons to the menu real quick so you can see what it looks like:


The above image is a sub nav that pops up when you click on "Projects" and I added icons to the first two sub-links using the new "icon URL" field added with the method I'm about to show you...


So to accomplish this, I started a new plugin called "Jafty Top Nav". I made a folder named jafty-top-nav and a file inside it named jafty-top-nav.php with the following contents:

* Plugin Name: Jafty Top Nav
* Plugin URI:
* Description: A Plugin that adds a custom top navigation menu to WordPress. This also adds the icon menu option to the WordPress admin, allowing one to select an icon to appear before submenu items in submenu dropdowns.
* Version: 1.0
* Author: Ian L. of
* Author URI:
* License: GPL2

//adds the Primary Jafty Menu location to wp-admin:
add_action('after_setup_theme', 'register_jafty_menu');
function register_jafty_menu(){
register_nav_menu('jafty-top-nav', __('Primary Jafty Menu', 'jafty-top-nav'));

//includes the library used to add custom fields to menu items:
require_once dirname( __FILE__ ) . '/menu-item-custom-fields/menu-item-custom-fields.php';

//include '';
include 'menu-item-custom-fields.php';

class Jafty_Walker extends Walker_Nav_Menu {

// Displays start of an element. E.g '<li> Item Name'
// @see Walker::start_el()
function start_el(&$output, $item, $depth=0, $args=array(), $id = 0) {
$object = $item->object;
$type = $item->type;
$title = $item->title;
$description = $item->description;
$permalink = $item->url;
$icon = get_post_meta($item->ID, 'menu-item-icon-url', true);
$output .= "<li class='" .  implode(" ", $item->classes) . "'>";

//Add SPAN if no Permalink
if( $permalink && $permalink != '#' ) {
$output .= '<img src="'.$icon.'" style="width:25px;float:left;margin-right:10px;margin-top:3px" /><a href="' . $permalink . '">';
} else {
$output .= '<span>';

$output .= $title;
if( $description != '' && $depth == 0 ) {
$output .= '<small class="description">' . $description . '</small>';
if( $permalink && $permalink != '#' ) {
$output .= '</a>';
} else {
$output .= '</span>';


The most important portion of code above I put in red text. That is where I retrieve one of the custom fields in order to display it in the nav menu. You will notice below that I named the field "icon-url" in the "jafty-custom-nav-fields.php" file and above I reference it with "menu-item-icon-url", so take notice of this so you don't cause an error.

Then I created a second file inside the same "jafty-top-nav-plugin" folder named "jafty-custom-nav-fields.php" which has the following code:

* Custom menu items metadata:
class Jafty_Custom_Nav_Fields {

* Holds our custom fields
protected static $fields = array();

* Initialize plugin
public static function init() {
add_action( 'wp_nav_menu_item_custom_fields', array( __CLASS__, '_fields' ), 10, 4 );
add_action( 'wp_update_nav_menu_item', array( __CLASS__, '_save' ), 10, 3 );
add_filter( 'manage_nav-menus_columns', array( __CLASS__, '_columns' ), 99 );

self::$fields = array(
//note that menu-item- gets prepended to field names
//i.e.: field-01 becomes menu-item-field-01
//i.e.: icon-url becomes menu-item-icon-url
'icon-url' => __( 'Icon URL:', 'jafty_custom_nav_fields' ),
'field-02' => __( 'Custom Field #2', 'jafty_custom_nav_fields' ),

* Save custom field value
* @wp_hook action wp_update_nav_menu_item
* @param int   $menu_id         Nav menu ID
* @param int   $menu_item_db_id Menu item ID
* @param array $menu_item_args  Menu item data
public static function _save( $menu_id, $menu_item_db_id, $menu_item_args ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {

check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );

foreach ( self::$fields as $_key => $label ) {
$key = sprintf( 'menu-item-%s', $_key );

// Sanitize
if ( ! empty( $_POST[ $key ][ $menu_item_db_id ] ) ) {
// Do some checks here...
$value = $_POST[ $key ][ $menu_item_db_id ];
} else {
$value = null;

// Update
if ( ! is_null( $value ) ) {
update_post_meta( $menu_item_db_id, $key, $value );
echo "key:$key<br />";
} else {
delete_post_meta( $menu_item_db_id, $key );

* Print field
* @param object $item  Menu item data object.
* @param int    $depth  Depth of menu item. Used for padding.
* @param array  $args  Menu item args.
* @param int    $id    Nav menu ID.
* @return string Form fields
public static function _fields( $id, $item, $depth, $args ) {
foreach ( self::$fields as $_key => $label ) :
$key   = sprintf( 'menu-item-%s', $_key );
$id    = sprintf( 'edit-%s-%s', $key, $item->ID );
$name  = sprintf( '%s[%s]', $key, $item->ID );
$value = get_post_meta( $item->ID, $key, true );
$class = sprintf( 'field-%s', $_key );
<p class="description description-wide <?php echo esc_attr( $class ) ?>">
<?php printf(
'<label for="%1$s">%2$s<br /><input type="text" id="%1$s" class="widefat %1$s" name="%3$s" value="%4$s" /></label>',
esc_attr( $id ),
esc_html( $label ),
esc_attr( $name ),
esc_attr( $value )
) ?>

* Add our fields to the screen options toggle
* @param array $columns Menu item columns
* @return array
public static function _columns( $columns ) {
$columns = array_merge( $columns, self::$fields );

return $columns;

The most important part of the above code is the field names. I changed the text color for the field names to red. However you also need to be aware that you have to append "menu-icon-url" to the field names when you go to fetch them in your header.php theme file later on so icon-url would become icon-url-menu-icon-url" for example...see the note above the code as well.

Then I used two files created by  Dzikri Aziz and put them in their own folder named "menu-item-custom-fields" inside of the jafty-top-nav folder. Here are the names and content of those two files if you are copy and pasting as we go:

menu-item-custom-fields.php content:


 * Menu Item Custom Fields

if ( ! class_exists( 'Menu_Item_Custom_Fields' ) ) :
    * Menu Item Custom Fields Loader
    class Menu_Item_Custom_Fields {

        * Add filter
        * @wp_hook action wp_loaded
        public static function load() {
            add_filter( 'wp_edit_nav_menu_walker', array( __CLASS__, '_filter_walker' ), 99 );

        * Replace default menu editor walker with ours
        * We don't actually replace the default walker. We're still using it and
        * only injecting some HTMLs.
        * @since   0.1.0
        * @access  private
        * @wp_hook filter wp_edit_nav_menu_walker
        * @param   string $walker Walker class name
        * @return  string Walker class name
        public static function _filter_walker( $walker ) {
            $walker = 'Menu_Item_Custom_Fields_Walker';
            if ( ! class_exists( $walker ) ) {
                require_once dirname( __FILE__ ) . '/walker-nav-menu-edit.php';

            return $walker;
    add_action( 'wp_loaded', array( 'Menu_Item_Custom_Fields', 'load' ), 9 );
endif; // class_exists( 'Menu_Item_Custom_Fields' )

// Uncomment the following line to test this plugin
#require_once dirname( __FILE__ ) . '/doc/menu-item-custom-fields-example.php';

walker-nav-menu-edit.php content:


 * Custom Walker for Nav Menu Editor
class Menu_Item_Custom_Fields_Walker extends Walker_Nav_Menu_Edit {

     * Start the element output.
     * We're injecting our custom fields after the div.submitbox
     * @see Walker_Nav_Menu::start_el()
     * @since 0.1.0
     * @since 0.2.0 Update regex pattern to support WordPress 4.7's markup.
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item   Menu item data object.
     * @param int    $depth  Depth of menu item. Used for padding.
     * @param array  $args   Menu item args.
     * @param int    $id     Nav menu ID.
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        $item_output = '';

        parent::start_el( $item_output, $item, $depth, $args, $id );

        $output .= preg_replace(
            // NOTE: Check this regex from time to time!
            $this->get_fields( $item, $depth, $args ),

     * Get custom fields
     * @access protected
     * @since 0.1.0
     * @uses add_action() Calls 'menu_item_custom_fields' hook
     * @param object $item   Menu item data object.
     * @param int    $depth  Depth of menu item. Used for padding.
     * @param array  $args   Menu item args.
     * @param int    $id     Nav menu ID.
     * @return string Form fields
    protected function get_fields( $item, $depth, $args = array(), $id = 0 ) {

         * Get menu item custom fields from plugins/themes
         * @since 0.1.0
         * @since 1.0.0 Pass correct parameters.
         * @param int    $item_id  Menu item ID.
         * @param object $item     Menu item data object.
         * @param int    $depth    Depth of menu item. Used for padding.
         * @param array  $args     Menu item args.
         * @param int    $id       Nav menu ID.
         * @return string Custom fields HTML.
        do_action( 'wp_nav_menu_item_custom_fields', $item->ID, $item, $depth, $args, $id );

        return ob_get_clean();

Then finally, the last thing you have to do is edit your header.php file for your current WordPress theme to include something like this where your to site navigation code appears:

<nav id="site-navigation" class="main-navigation" role="navigation">
            <button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false"><?php esc_html_e( 'Primary Jafty Menu', 'jafty-theme' ); ?></button>
            <?php wp_nav_menu( array( 'theme_location' => 'menu-1', 'menu_id' => 'primary-jafty-menu', 'walker' => new Jafty_Walker() ) ); ?>
        </nav><!-- #site-navigation -->


That's all there is to it. I know it's a lot, but if you start out by copy and pasting my code and following instructions carefully to recreate the above jafty-top-nav plugin, it should work fine. Afterwards, you can edit it to fit your own personal requirements as needed. Good luck!


I want to give credit for the help I got on this technique, but frankly I saw the same code in different areas online and don't know which is the correct site to link to, but in one of the files, the author gave his name, which was Dzikri Aziz, so I'd like to extend my thanks to Dzikri Aziz for helping me bring this code to life. If I find a link I'll post it or if anyone knows it, please comment and I'll make sure he gets the appropriate credit for his portion of the code I used in this article.