Category Archives: Server Administration

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!

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!


How to Clone a MYSQLI Table From Command Line

Here are the two commands you can run from the Mysqli Command Prompt to successfully clone a database table. In the example we will name our tables new_table_name and old_table_name where old_table_name is the table we wish to clone. This is the best way I have found to-date to create a backup of a mysqli table from the command line:

CREATE TABLE new_table_name LIKE old_table_name;
INSERT new_table_name SELECT * FROM old_table_name;

Be sure to enter line one above and press enter, then do the same with the second line.

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 Figure Out Relative Humidity with PHP

Today, I had to calculate relative humidity using PHP and I have documented my findings below:

First, let's just use an example situation where we have a temperature of 60.1 and a dew point of 42.7, both in Fahrenheit, so...:

dew point in Fahrenheit: 42.7

temperature in Fahrenheit: 60.1

1) The first step is to convert to Celsius using the following formulas


Formulas explained:
Tc=air temperature in degrees Celsius, Tf=air temperature in degrees Fahrenheit

Tdc=dewpoint temperature in degrees Celsius

Tdf=dewpoint temperature in degrees Fahrenheit

Notice: If your temperature and dewpoint are in degrees Celsius, you can skip step 1 and proceed to step 2.

answer for equations:
Temp in Celsius: 15.61

0.5555555555555556 * 28.1 = 15.61111111111111

dewpoint in Celsius: 5.94
0.5555555555555556 *  10.7 = 5.944444444444444

2) calculate saturation vapor pressure(Es) and actual vapor pressure(E) in millibars:
NOTE: first line is the equation and the subsequent lines represent one step solved at a time:
Es=61.1 ** (7.5*15.61/(237.7+15.61))
Es=61.1 ** (117.075/253.31)
Es = 61.1**0.4621807271722395
Es = 6.6907349413770067935260257174923

E=61.1 ** (7.5*5.94/(237.7+5.94))
E=61.1 ** (44.55/243.64)
E=61.1 ** 0.1828517484813659497619438515843
E = 2.1211957981192776150462474985589

3)  Once you have the saturation vapor pressure and actual vapor pressure, relative humidity(RH) can be computed by dividing the actual vapor pressure by the saturation vapor pressure and then multiplying by 100 to convert the quantity to a percent:
RH =(E/Es)*100
RH =(2.1211957981192776150462474985589/6.6907349413770067935260257174923)*100
RH = 0.31703479762758596814611114744566 * 100
RH = 31.703479762758596814611114744566%
SO... Humidity is 31.7%

And note here that ** means to the power of. I figured I'de clue anyone in that is as ignorant is I was when I had to figure it out.

How to Search and Replace File Names

A lot of times I am required to rename large quantities of files according to various rules. Sometimes this task can take hours to complete. Today I had a job requiring me to rename all files in a program that contained "xi" with "nap". The program had thousands of files in a dozen different directories. It would have taken days for me to go through them all manually and replace ea. occurrence of "xi" in the file names with "nap", so I tested several tools to help me do the job. The most capable tool I found was named simply "ReNamer" and can be downloaded from:

I downloaded the "portable" version of ReNamer version 6.7 Here is a screenshot of ReNamer's simply UI:

How to Download and Open ReNamer for First Use

First things first, so here is how to get started:

Use the link to download the portable version of ReNamer and it will download a zip file to your PC. Place the file on your desktop and right click it and select "Extract All". Windows will extract the files and probably open the folder for you. Then click on renamer.exe to start the app. You will see the UI as in the above image. I like using this portable version because it is very light-weight and can be used on any PC. When I'm done using it, I simply delete the entire unzipped folder but I save the .zip folder I downloaded so I can use it again when needed and it doesn't waste any space on my PC when it's not in use. Next time I need it, I simply extract the files again and use it. Then I delete the folder when done again.

Find and Replace Text in File Names of Many Files at Once

It is easy as pie to use too! It only took me a couple of test runs to achieve the renaming rules I needed to do the job at hand. Just  click where it says "Click here to add a rule" and add a rule. I needed to find and replace text in the file names, so in my case, I clicked on "replace" in the left panel so the add rule screen looks like this:



All I had to do was simply enter "xi" in the "find" field and "nap" in the "replace" field and click the "Add Rule" button to save your new rule. Then all you have to do is drag the folder containing all the files you want to rename into the UI as in the first image above, where it says "Drag Your Files Here". Then it gives you a preview of what files it will rename. Once you are happy with how it's doing the renaming, click the "Rename" button in the upper right corner of the UI and it will rename all of the files just like it showed you. If you have tested any of the other features of this tool, please comment below and describe your experience!

Enabling Multiple Domain Names and Sites on Apache2 Server

Today I set up a new server and I am documenting exactly how to set up multiple domain names, sub domains and websites on a new Apache2 Server. I am using Ubuntu, but I believe these directions are similar for any Linux Apache2 web server.

Pointing your domain or sub-domain

It is a good practice to point your domain name or sub-domain first, before you set it up on your server which I'll cover afterwards below, so let's go ahead and point our domain. Whether you are using a new domain name or a sub-domain on one of your existing domain names, the process is similar for pointing the domain name or sub domain name to your server IP address. You will need to go to your domain management console and create a Type "A" record. This will normally be done in your DNS provider's advanced DNS settings or zone file settings. Use the following settings to create two new records:

  • Name: if there is a name field, enter the domain name or sub-domain name(most require you to follow the domain with a "." so for my sub domain I entered "".
  • Type: "A" for both records.
  • Hostname field: enter "www" in the first record and "@" in the second.
  • Destination IPv4 address(sometimes just called Address): Use your server's IP address for both records.
  • TTL: use "14400" for both records.

That should be enough information for you to figure out how to create your two host records on just about any platform, but if your platform differs, ask your provider for assistance or google the providers name followed by DNS instructions or "How to point a name with Provider Name". You are creating two similar records, one for WWW and one for @. That way visitors of your site can access with either or just The Hostname of @ makes the record for the domain without "www" in front of it. If your provider's DNS settings do not include the Host or Hostname field where we put either www or @, then you probably need to create two records with different names instead. For example, name one record "" and name the other "". If you're using a sub domain then name one "" and the other "" You don't really need a www record for sub domains usually, but you can use one if you want, it won't hurt anything and might help some users find your site.

Steps to adding  a second domain name to your server

Here I am going to explain how I set up a sub domain as as second domain name pointing to a second website on my Linux/Apache2 web server:

Note: My first site was already set up in var/www/html. Most people prefer to set up multiple websites under the var/www directory, but to keep things simple, I'm going to use the var/www/html folder and not var/www. It really makes no difference. It's just a preference.

  1. Create your directory structure for your new website that will reside on your new domain or sub-domain. I'm creating a sub domain like, but these directions are the same as if I were using just instead. First, create the directory /var/www/html/ Then create /var/www/html/ and /var/www/html/ If you are logged into FileZilla as root, you can create these from there, otherwise log in with putty and create them using the sudo command.
  2. Create your log files. Simple make two empty files named access.log and error.log and upload them to the logs folder you created in step one above.
  3. Create a VHOSTS file named after the domain or sub-domain followed by .conf, so in my case, I'd name my file THen copy and paste the  content below under the heading "VHOSTS Example File Contents" into it then change all instances of my sub-domain name with your own domain or sub domain and upload that file to /etc/apache2/sites-available.
  4. Next, use the a2ensite tool from the Linux command line to finalize the new site with the following command(replace with your domain or sub-domain):  sudo a2ensite
  5. Reset apache2 with: sudo service apache2 restart

VHOSTS Example File Contents

<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

Automating the process of setting up domain names and sub domains

If you have to do this often or alter DNS records often and create lots of virtual hosts, you should probably look into automating the process. I provide such a service and have done so for several of my clients. What I do is create a simple user interface in a secure admin web page on your own server where you can simply enter the domain name or sub domain name into a form field and press GO and it does all the above work for you! A real time saver if you have to do this more than once in a great while! IF you are interested in this service, contact me, Ian L. of for a fast, free quote by email or Skype. My email is and my Skype name is ianlin11. Or use the contact link on this site.


That is how you do it!

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.

Get IP Address from Domain Name

Domain name:

Returns the IP address associated with the domain name you enter into the form. It will return a list of IP addresses if more than one is associated with the given domain name.

NGINX New Site Creation and Server Configurations

Today I'm going to share with my readers my list for manually creating another website on one of my NGINX servers. I am partially logging this here for my own reference as I often look for these directions I keep stored in a .txt file on my laptop. Wherever you see text in green in this post, it will indicate that the text is to be entered as a command at the command prompt in Linux.

Step by Step Directions to Add a New Site on NGINX Servers

1) Sign into Linux server using an application like Putty (Windows) or Terminal (Mac):

Login with root user and password if possible, otherwise login with the user and password you have and remember to use sudo commands(purring sudo before each command line command)

2) Create the website directory (for example,

mkdir -p /var/www/
mkdir -p /var/www/

3) Change the ownership of the directory to the web user:
chown -R www-data:www-data /var/www/
chown -R www-data:www-data /var/www/

4) Create the web site config file. To do this, you can simply copy the config file of an existing site and then make the required changes. For example try this command but change the existing_site to your own existing website on your server:
cp /etc/nginx/sites-available/ /etc/nginx/sites-available/

5) Edit the new config file to replace with the new site’s values:

nano /etc/nginx/sites-available/
Edit the line that reads: root /var/www/ to be the current domain name.
Edit the two server_name instances to be the new domain name.
Edit access_log and error_log paths for new domain name
Save the file by hitting Ctrl-X, then Y and then Enter.

6) Enable the new site in NGINX:

ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

7) Restart NGINX:

service nginx restart

9) Create the database and user.

mysql -u root -p
create database database name;
(note: I often create the db and user with the same name as the domain name. That makes it easy to remember. However, MySQL users are limited to 16 characters. so if the domain name is longer, I truncate both in some fashion. Just make sure theu match.
grant all on your_new_site.* to 'your_new_site' identified by 'secret_password';
(the last part is the password. just make up a hard one - record this where only you can find it, you’ll need it with the restore)

8) Copy your new website files into the public_html folder with your sFTP client and your site is up and running!

Using PHP to create an NGINX SITE MAKER

I used the above knowledge to create a Site Maker tool that does all the steps for you. All you have to do is enter a domain name. Email me if interested at


So, this isn't too hard if you have something to reference such as the above cheat sheet. Once you get used it doing it, it is really easy. However if it's too complex, you can do what I did and make a tool to do it for you. Even if it's not too difficult, the tool saves you time if you add a lot of sites to your NGINX server as I do. Email me if you have interest in such a tool and I can custom build you one for your server! is my email.

How to Remove Slugs for a Custom Post Type in WordPress

So, back in the day, not to long ago, one could remove slugs in a CPT(Custom Post Type), simply by adding the following line to the arguments array when calling the register_post_type function:

'rewrite' => array('slug' => ''),//NOT THE SOLUTION!

However, that no longer works as of WordPress version 4.7.?, so I put together the following two function from various other solutions I've seen. This solution works for a single post type or multiple post types. I am publishing it because I haven't seen any elsewhere that could handle more than one CPT at a time. I wrote this to remove slugs for two CPTs, but you could us it for one or as many as you want, the two functions are as follows and can be added to functions.php or, as I do, to a plugin file, below the register_post_type functions:


//Two functions to remove slug from team_member and event CPTs:
function remove_evil_slugs($post_link, $post, $leavename) {

    if('team_member' != $post->post_type || 'event' != $post->post_type ||'publish' != $post->post_status) {
        return $post_link;

    $post_link = str_replace('/' . $post->post_type . '/', '/', $post_link);

    return $post_link;
add_filter('post_type_link', 'remove_evil_slugs', 10, 3);

function  parse_evil_slugs($query) {

    if(!$query->is_main_query() || 2 != count($query->query) || !isset($query->query['page'])) {

    if(!empty($query->query['name'])) {
        $query->set('post_type', array('post', 'team_member', 'event', 'page'));
add_action('pre_get_posts', 'parse_evil_slugs');


Those are the two functions that accomplish the goal. Simply replace all occurrences of "team_member" and "event" with the names of your own custom post types. If you use any rewrite rules in the args parameter for the register_post_type function, comment it out. For example if you see anything that looks like this:

'rewrite' => array('slug' => ''),


'rewrite' =>false,

...either comment it out of delete it all together from the function that creates the custom post type(CPT).

Update 3-27-2017

I've noticed that on some servers, the above solution no longer works, so I was able to program a new solution for NGINX servers. If your server is not an NGINX server, I found a solution here that should work for all even though it is a bit outdated: The code below is code I wrote based on that link but updated for nginx servers:

class JAFTY_CPT_SlugKiller{
    static $_s = null;
    private $htaccess_tag = 'SLUG KILLER REMOVE SLUG RULES';
    public function __construct() {
        add_action('wp_insert_post', array(&$this, 'post_save'));

        add_filter('post_type_link', array(&$this, 'remove_slug'), 10, 3);
    static public function init() {
        if (self::$_s == null) {
            self::$_s = new self();
        return self::$_s;
    static public function flush_rewrite_rules() {
        $jafty_o = self::init();

    public function post_save($post_id) {
        global $wp_post_types;
        $post_type = get_post_type($post_id);
        foreach ($wp_post_types as $type=>$custom_post) {
            if ($custom_post->_builtin == false && $type == $post_type) {
    public function remove_slug($permalink, $post, $leavename) {
        global $wp_post_types;

        foreach ($wp_post_types as $type=>$custom_post) {
            if ($custom_post->_builtin == false && $type == "team_member") {
                $custom_post->rewrite['slug'] = trim($custom_post->rewrite['slug'], '/');
                $permalink = str_replace(get_bloginfo('url') . '/' . $custom_post->rewrite['slug'] . '/', get_bloginfo('url') . "/", $permalink);
        return $permalink;
    public function rewrite_rules($flash = false) {
        global $wp_post_types, $wpdb;
        foreach ($wp_post_types as $type=>$custom_post) {
            if ($custom_post->_builtin == false && $type == "team_member") {
                $querystr = "SELECT {$wpdb->posts}.post_name
                                FROM {$wpdb->posts}
                                WHERE {$wpdb->posts}.post_status = 'publish'
                                        AND {$wpdb->posts}.post_type = '{$type}'
                                        AND {$wpdb->posts}.post_date < NOW()";
                $posts = $wpdb->get_results($querystr, OBJECT);
                foreach ($posts as $post) {
                    $regex = "{$post->post_name}\$";
                    add_rewrite_rule($regex, "index.php?{$custom_post->query_var}={$post->post_name}", 'top');            
        if ($flash == true)
    private function add_rules_htaccess() {
        global $wp_post_types;
        $suffix = get_option('jafty_permalink_customtype_suffix');
        $write = array();
        $htaccess_filename = ABSPATH . '/.htaccess';
            $htaccess = fopen($htaccess_filename, 'r');
            $content = fread($htaccess, filesize($htaccess_filename));
            foreach ($wp_post_types as $type=>$custom_post) {
                $rewrite_rule = (!empty($suffix))
                            ? "RewriteRule ^{$custom_post->query_var}/(.+)/\$ /\$1\.{$suffix} [R=301,l]"
                            : "RewriteRule ^{$custom_post->query_var}/(.+)/\$ /\$1 [R=301,L]";
                if (strpos($content, $rewrite_rule) == false && $custom_post->_builtin == false)
                    $write[] = $rewrite_rule;
            add_action('admin_notices', array(&$this, 'compatibility_notice'));
        if (!empty($write) && is_writable($htaccess_filename)) {
            $new_rules = '# BEGIN ' . $this->htaccess_tag . PHP_EOL;
            $new_rules .= str_replace('$', '\\$', implode(PHP_EOL, $write)) . PHP_EOL;
            $new_rules .= '# END ' . $this->htaccess_tag;
            if (strpos($content, "# BEGIN {$this->htaccess_tag}") === false) {
                file_put_contents($htaccess_filename, $new_rules . PHP_EOL . PHP_EOL . $content);
            else {
                $pattern = "/# BEGIN {$this->htaccess_tag}.*?# END {$this->htaccess_tag}/ims";
                $content = preg_replace($pattern, $new_rules, $content);
                file_put_contents($htaccess_filename, $content);
        }else if(!is_writable($htaccess_filename))
            add_action('admin_notices', array(&$this, 'compatibility_notice'));
    }//end add_rules_htaccess function

    public function compatibility_notice() {
        global $wp_post_types;
        $rules = '';
        foreach ($wp_post_types as $type=>$custom_post) {
            if ($custom_post->_builtin == false && $type == "team_member") {
                $slug = str_replace('/', '', $custom_post->rewrite['slug']);
                $rules .= 'RewriteRule ^' . $slug . '/(.+)$ /$1 [R=301,L]<br />';
        echo '<div class="error fade" style="background-color:red;"><p><strong>Remove Slug Custom post type error!</strong><br />.htaccess is not writable, please add following lines to complete your installation: <br />'.$rules.'</p></div>';
}//End JAFTY_CPT_SlugKiller class to remove slugs from team_member CPT

//actions and hooks for above class to remove slug from team_member CPT:
add_action('init', array('JAFTY_CPT_SlugKiller', 'init'), 99);
//the following two lines make it so you don't have to manually go to settings/permalinks and re-save settings for links to work:
register_activation_hook( __FILE__, array('JAFTY_CPT_SlugKiller', 'flush_rewrite_rules') );
register_deactivation_hook( __FILE__, array('JAFTY_CPT_SlugKiller', 'flush_rewrite_rules') );


The above code can be added to a plugin file or your themes functions.php.

NOTE: although the above code hasn't been thoroughly tested on non-nginx servers, it should work if you un-comment the two lines that call the add_rules_htaccess function. Simply do a search for "add_rules_htaccess" and remove the "//" before it in two occurrences and this code should work on any server as long as your .htaccess file is writable.

Building a Custom WordPress Navigation Menu Plugin

This is a semi-advanced WordPress tutorial so you should have a little bit of existing knowledge of WordPress if you want to be able to understand the concepts involved. I will try to make it as easy to follow as possible none-the-less.

We are just going to dive right in a create a new Plugin. I'll be calling the plugin Jafty-Nav, you can follow suit if you wish to keep things simple or give it your own name if you feel comfortable making such changes.

Create a New Plugin

* Plugin Name: Jafty Top Nav Plugin
* Plugin URI:
* Description: A Plugin that adds a custom top navigation menu to WordPress.
* Version: 1.0
* Author: Ian L. of
* Author URI:
* License: GPL2

Register a New Menu Location with WordPress

Add this PHP code to your plugin file you created above:

add_action('after_setup_theme', 'register_jafty_menu');
function register_jafty_menu(){
  register_nav_menu('jafty-top-nav', __('Primary Jafty Menu', 'jafty-top-nav-plugin'));

Now that is actually enough to create a simple plugin. The plugin will add a menu location to wp-admin and that's it, but we'll build on it after we install it. So go ahead and install the plugin by putting it into a folder named "jafty-top-nav-plugin" and naming the file "index.php". Then upload to your WordPress plugins directory. Activate the Jafty Top Nav Plugin then go to your admin and click on "Appearance/Menus" then select the "Manage Locations" tab and you'll see the new menu location your plugin as added to the admin like in the image below.


Placing a new top nav in your theme

The next task is to edit your current WordPress theme to work with the Jafty Top Nav Plugin. You'll need to create a new header file and edit your page, post and/or home page templates to contain your new top navigation menu. Here is how:

  1. Go into your current theme's folder and download a copy of the header.php file to your desktop and rename it header-jafty.php.
  2. open header-jafty.php in notepad and find the section that looks something like this:<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 Menu', 'outer-gain-dev' ); ?></button>
    <?php wp_nav_menu( array( 'theme_location' => 'menu-1', 'menu_id' => 'primary-menu' ) ); ?>
  3. Inside the code within the Nav tag in your header-jafty.php file, change the theme_location value to 'jafty-top-nav' and save the file.
  4. Now upload your header-jafty.php file to your active theme's folder.
  5. Next you'll want to add the new header to your template files, Some templates you might want to do this too are front-page.php, single.php, page.php and any custom page templates in your theme or child theme you might have. The process is very similar for adding the new header to any of the files, so I'll just demonstrate on the home page template file, front-page.php. Open the template file in your notepad and near the top of the code you should see something like this:
    or you may have something like this instead:
    Regardless which you have, replace the line with:
    and that will call your new header.jafty.php template into the page template so your customized header will be shown.
  6. Save and upload your altered template file and repeat for all necessary page and post templates until you have your new top nav menu at the top of all desired pages and/or posts throughout your entire WordPress site.

Now that we have more control of it, let's customize that ugly top nav!

Customizing the WP Navigation Menu

It's time to get down and dirty with some real-world customization of the top navigation menu in WordPress. We are not just doing some simple CSS changes here, we are talking about a complete rewrite of the navigation system. This is why I went with a plugin for this. Now I had to find what WordPress core functions I could use to alter the menu completely. My goal is to make a menu similar to the one at, which is not a WordPress site by the way. I just love the dynamic drop downs that fade in and out and their use of icons in the sub-menu items. I'll get to how I duplicated all of that later on, first we need to know how to rebuild the entire menu structure because the style menu is nothing like a standard WordPress menu. Here's what I figured out:


First we need to be able to retrieve our custom navigation links from the WordPress backend. Remember earlier we created a menu location? Well, we need to retrieve the menu assigned to that particular location in WordPress. Therefore the first thing we want to do is make sure there is a menu assigned to the "Primary Jafty Menu". You could pick one from the drop down, but we want to make a new one that is sure to have both main menu items and sub menu items so we can adequately test our menu when it's complete. Therefore we locate the "Primary Jafty Menu" and click the link to the right of it that reads "Use New Menu" as I've circled in red in the below image:


When creating the new Primary Jafty Menu, give it a name of "Jafty 1". It's best to do everything exactly as I have done just to be sure you don't have any conflicts. You can always change names and such after you have a completed working plugin. When creating the menu, make sure to add at least 2 main menu items with at least 2 sub menu items each so we can test the drop down effects. Here is an image of the one I made for testing. If you don't have enough pages or posts to make that many links, don't worry, just use two real links for the main menu items and click on "custom links" and create outside links for all of your sub menu items as I have done in the below image:


In the above image, "site settings" and "Hello world!" represent our two main menu items and the sub links rest below them indented to show their sub-link status. Notice I have "Primary Jafty Menu" checked under "Menu Setings" too. Once you have your menu, be sure you save it. Now we can return to developing our plugin!

Retrieve Menu and Sub Menu Items from WordPress Admin

It is time to develop some custom WordPress code to extract out menu items and sub-menu items from the database. Lucky for us, WordPress has some built-in core functions to assist us. Here is the code I come up with to extract all menu and sub-menu items for the "Jafty Primary Menu" from the database to display them on the front-end:

      $menuLocations = get_nav_menu_locations(); // Get nav locations
      $menuID = $menuLocations['jafty-top-nav']; //menu assigned to Jafty Primary Menu
      $theNav = wp_get_nav_menu_items($menuID);
                    foreach ($theNav as $navItem) {
                        //get the url for the link:
                        $navURL = $navItem->url;
                        //get the nav link text/title:
                        $navTXT = $navItem->title;
                        //Get the nav link's ID:
                        $navID = $navItem->ID;
                        //Get menu item parent(will be 0 if main link or parent ID if it's a sub link):
                        $navParent  = $navItem->menu_item_parent;
                        echo "ID: $navID, $navTXT, $navParent, $navURL<br />";
                    //echo '<li class="has-dropdown gallery" data-content="about"><a href="'.$navURL.'" title="'.$navItem->title.'">'.$navTXT.'</a></li>';

The above code will go in out header file named header-jafty.php. Lets examine the code so you understand what it does.

The first line:

$menuLocations = get_nav_menu_locations(); // Get nav locations

as the comment says afterwards, it gets the navigation menu locations stored in WordPress. We added one of these in the beginning of the tutorial using the register_nav_menu function.

The second line reads:

$menuID = $menuLocations['jafty-top-nav']; //menu assigned to 'Primary Jafty Menu'

This line fetches the ID of the menu currently assigned to the menu location we created in the plugin file, "Primary Jafty Menu". We then use the id in the next line that reads:

$theNav = wp_get_nav_menu_items($menuID);

We now have a WordPress menu object stored in $theNav. If you do a print_r($theNav) command in PHP, you would see that the menu object holds all sorts of information about the menu we created earlier. However, we only need four key pieces of information from the menu object. We need to get:

  1. The Link URL
  2. The Link Text
  3. The Link ID
  4. The Link's Parent ID in case it is a sub-menu item.

We can get the four pieces of information we need using a foreach loop on the $theNav object like so:

     foreach ($theNav as $navItem) {
                        //get the url for the link:
                        $navURL = $navItem->url;
                        //get the nav link text/title:
                        $navTXT = $navItem->title;
                        //Get the nav link's ID:
                        $navID = $navItem->ID;
                        //Get menu item parent(will be 0 if main link or parent ID if it's a sub link):
                        $navParent  = $navItem->menu_item_parent;
                        echo "ID: $navID, $navTXT, $navParent, $navURL<br />";
                    //echo '<li class="has-dropdown gallery" data-content="about"><a href="'.$navURL.'" title="'.$navItem->title.'">'.$navTXT.'</a></li>';

We now have all the information we need about the menu items after running the above foreach loop on the menu object. We have the link text, URL, ID and Parent ID. It's important to note that the parent ID will always be 0 if the link is a main menu item and we can determine if the link is a sub-menu item if the parent ID is anything other than zero. Then we know which link to put the sub-link under by matching the sub-link's parent ID to the ID of the main link item. Pretty simply really, once you get accustomed to it.

Now we need to open our header-jafty.php file and find the line that reads something similar to:

<?php wp_nav_menu( array( 'theme_location' => 'jafty-top-nav', 'menu_id' => 'primary-menu' ) ); ?>

And replace it with the code we wrote above:

$menuLocations = get_nav_menu_locations(); // Get nav locations
$menuID = $menuLocations['jafty-top-nav']; // Get the *primary* menu ID
$theNav = wp_get_nav_menu_items($menuID);

foreach ($theNav as $navItem) {
//get the url for the link:
$navURL = $navItem->url;
//get the nav link text/title:
$navTXT = $navItem->title;
//Get the nav link's ID:
$navID = $navItem->ID;
//Get menu item parent(will be 0 if main link or parent ID if it's a sub link):
$navParent  = $navItem->menu_item_parent;
echo "ID: $navID, $navTXT, $navParent, $navURL<br />";
//echo '<li class="has-dropdown gallery" data-content="about"><a href="'.$navURL.'" title="'.$navItem->title.'">'.$navTXT.'</a></li>';

Now save your header-jafty.php file and upload it to your active theme's folder and refresh your home page. You should see the following information printed in the header area of your site instead of a top nav now:

ID: 47, Site Settings, 0,
ID: 49, Jafty Interactive, 47,
ID: 50, Jafty Blog, 47,
ID: 48, Hello world!, 0,
ID: 51, Yahoo Search, 48,
ID: 52, Google Search, 48,

As you can see my site returned 6 lines of text in the header, one for each of the two main menu items and one for each of the four sub-menu items in the menu I created in wp-admin. Each of the lines above contains the main ID first, followed by the link text, then the parent ID and finally the link text. I highlighted the parent IDs in blue so you can see how the two main menu items have a parent ID of zero while the other four have parent IDs equal to the two main menu items with zero for parent ID. Make sense? I hope so:-)

For all you professional WordPress plugin developers, I can probably stop there. Now you have enough to make your own custom top navigation menu for your WordPress theme. You clearly don't need to do this as a plugin, in fact, it would normally done by adding the plugin code to functions.php in the current theme instead. I am making it a plugin just as a learning exercise.

You can use the information it printed in your header to figure out how to add in the HTML and CSS for any type of custom nav you desire, or you can read on to see how I recreated the top nav for one of my clients.

Make a Static Top Navigation Menu as a Demo

Before we go about coding the menu into WordPress, I like to create a static version first. I created mine based on looking at the top nav found on You can click the link to see what I mean. I didn't copy it by any means, but I did use it as a model for creating a similar one with similar transition effects. In the static demo, I didn't create great detail in the drop downs. Instead I concentrated on getting the transition effects and infrastructure perfect. I can worry about making the content of the dropdown boxes look pretty when I code it into the actual WordPress site. Here is my static demo:

I won't post all of the code to my static navigation menu demo here but you may feel free to use the link provided and use your browser's view source option to see how I made it and copy it if you so desire.




WordPress now has Post Templates

Great news for some WordPress developers, WordPress version 4.7 recently came out with an exciting new feature! They now allow post templates similar to the way page templates work.

Activating Post Templates

To activate the new post template feature all you have to do is add your first post template. The one requirement to make them show up in the admin area on the new or edit post screen is that you have to add the following lines to the very top of your new template files:

* Template Name: Your Post Template Name Here
* Template Post Type: CPT, names

That's all there is to it! Make up a template name for the first parameter and use the Custom Post Type name or names for the second parameter, Template Post Type:.

Lets say you created a custom post type named "movies" and you created a template named movie-posts.php, then your movie-posts.php file would start out like this:

* Template Name: Movie Posts
* Template Post Type: movies

Then go ahead and add your loop and other code to your template file and when you upload it you'll see a new "template" drop-down appear under the attributes heading in the right column of the edit posts and add new posts screen for that custom post type:



Note that this also works with ACF plugin or Advanced Custom Fields Pro plugin. That should explain it all. I hope this becomes as useful for some of my readers as it already has for me!

The WordPress Loop

Today I finally decided to dedicate a single tutorial on the wonderful WordPress loop. I will demonstrate how to create a basic loop and show several examples of the loop in action. The loop is what gets post and/or page data in WordPress template files, so if you ever have a need to make a custom page or post template, you'll need to understand how the loop works.


The Basic WordPress Loop

Most often you will see the loop look something like this:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

<!------------This is where you present your post data....-------------->

<?php endwhile; else : ?>
    <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>

The above example doesn't contain the middle part of the loop in order to demonstrate where the loop typically begins and ends. That way you can find the loop in your current theme and work with it by knowing where it starts and stops at least.  Next we'll discuss what to put in between where it says <!------------This is where you present your post data....-------------->.

Fetching Data Inside a WordPress Loop

Post Title:

First I'll show you how to display the Title as a link to the Post's permalink.

<h2><a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>

Just place the above code example where it says you present your post data in the the loop example above.

Post Content:

You can display the Post's content in a div with the following code inside of your loop:

<div class="entry">
<?php the_content(); ?>

Again, use the above code in between the starting and ending loop code explained above and this will display the general content of the post as entered into the standard WYSIWYG editor in the WordPress admin.

Using More Than One Loop

If you need to use two more more loops in the same template file, then you will have to reset the WordPress loop with rewind posts function like this:

<?php rewind_posts(); ?>

Just use the above line before your second loop and any loops afterwards and they will reset and be ready to function again.


Understanding IP Addresses

Have you ever needed to know how an IP Address works? Have perhaps just wondered how they worked? Well in my line of work it has eventually become necessary for me to fully understand exactly how IP addresses work and are made up. Therefore I aim to share my knowledge on such with anyone who cares to read about IP addresses here on my wonderful blog.

First of all it's important to know that IP addresses are displayed in what is known as dotted-decimal format. For example your current IP address is

For anyone Interested, I got your IP address using the following PHP code:

$ipaddress2 = $_SERVER[REMOTE_ADDR];
echo "<h3>Your Current IP Address: $ipaddress2</h3>";

Just notice the format of the IP address above for now though.

Two Main Parts of an IP Address

While an IP address appears to have 4 parts due to the dotted-decimal format used, in reality, IP addresses are made up of only two main parts. They are "Network ID" and "Host ID". The two parts are not equal or consistent. The Network ID is defined first and the Host ID will be the remaining portion of the IP address.

IP Address Classes

IP addresses are divided into different classes. There are actually five IP classes, but only three are in common use, they are Classes A,B, and C. Classes D and E are reserved classes. Class D is Reserved for Multicasting. Class E is Experimental; used for research. The three main classes are shown in the following examples:

  • Class A - Class A IP addresses use 8 bits for the Network ID(8 bits = 1 byte or 1 segment in dotted-decimal format or 1 octet). Class A addresses only include IP addresses from 1.x.x.x to 126.x.x.x. The IP range 127.x.x.x is reserved for loopback IP addresses. Therefore a Class A IP address might look like From what we know about the two parts of an IP address now, we know that the "19." portion of this example IP address defines the Network ID and the  remaining part(23.20.100) represents the Host ID.
  • Class B - Class B IP addresses use 16 bits for the Network ID(16 bits = 2 bytes or 2 segments in dotted-decimal format or 2 octets). The remaining 16 bits are used for the Host ID of course.
  • Class C - Class C IP addresses use 24 bits for the Network ID(24 bits = 3 bytes or 3 segments in dotted-decimal format or 3 octets). The remaining 8 bits are used for the Host ID in this case.

How to Determine IP Address Class

Determining whether an IP address belongs to class A, B or C can be a daunting task if you don't understand how IP addresses function. That is why I will explain it clearly here for you! First you need to realize that IP classes are determined by the first few bits of the IP address. Then you need to know that bits are not the same as the dotted-decimal format you are accustomed to! For example My IP address now shows as if I open this post in my current browser. What class does belong to? Well here is how I found out:

First, convert the dotted-decimal formatted IP address of to its binary form and count the bits. Actually, you can do just the first octet or 173 in this case. Here is how to convert a decimal octet to a binary Byte:

You divide the number(173 in this case) by 2 and take the answer with the remainder and note both. Then divide the answer by two and note the answer and remainder this eight times. Start at the top of a sheet of paper and move to a new line each time you start a new calculation.  Be sure to circle the remainder each time as those are the 8 bits that make up the Byte we are after. Here is my sloppy example of how I did it with my IP address that began with 173:

binarypaper_ink_li Notice that I circled the remainder after each division problem above. The final step is to start at the bottom and write each circled remainder down in order.

So from the image above, I get the binary number: 10101101

The first three bits of the binary 10101101 determine it's class. In my case, the first three bits are 101.

Then refer to the following table to determine your class:

  • CLASS A: the binary will begin with a zero.
  • CLASS B: the binary must start with 10.
  • CLASS C: the binary must start with 110.

So as you can see from the above table and the image above that, my IP address of converts to a binary number of 10101101 and can then be identified as a CLASS B IP address because its binary form begins with 10. Alot to do to figure out the class of an IP, but it is mostly for learning purposes that I have explained it all like I have. Really, all you have to do is refer to the following table of information which will allow you to convert it to a class using just the first octet of the IP address(173 in my case):

Quick & Easy Method to Determine IP Class

  • CLASS A: First 3 digits of the IP address will be from 0 to 127.
  • CLASS B: First 3 digits of the IP address will be from 128 to 191.
  • CLASS C: First 3 digits of the IP address will be from 192 to 223.

So again, my IP( starts with 173 so I can use the above three lines of data to confirm that it is indeed a CLASS C IP address because 173 falls in between 128 and 191.



mysqli_result function to replace old mysql_result

Many of us are busy upgrading our PHP and MySQL code when migrating from PHP5 to PHP7. One of the first things you learn is that the MySQL functions have been depreciated and removed completely in PHP7, therefore can no longer be used! That's a major pain in the butt for many of us, but luckily the fix is not too difficult most of the time. Simply doing and find and replace replacing "mysql" with "mysqli" is often a good first step, but you will also need to add the connection variable as an argument to many of the mysqli functions as well. Then some functions, such as the mysql_result function, do not have a mysqli counterpart. That means there is no mysqli_function defined in PHP7! Real pain right? well copy and paste the following functino into your PHP code and you can now use the mysqli_result function effectively. Be sure to pass it the connection variable as most mysqli functions require even though mysql counterparts did not. Here's the function:

function mysqli_result($res,$row=0,$col=0){ 
    $numrows = mysqli_num_rows($res); 
    if ($numrows && $row <= ($numrows-1) && $row >=0){
        $resrow = (is_numeric($col)) ? mysqli_fetch_row($res) : mysqli_fetch_assoc($res);
        if (isset($resrow[$col])){
            return $resrow[$col];
    return false;

Find a file using Linux find Command

If you need to find a file anywhere on a server, what directory it is in or not, the Linux Find command is your go to command! Here are some basic usage cases:

Find a file in the current directory:

find . -name "this-file.php"

Find a file anywhere on the server above the root directory:

find / -name "filename.php"

Notice in the first example we used a period and in the second we used a forward slash. The period means to search the current directory and the forward slash means to search from the root directory and will basically find a file anywhere on the file in the root directory or any of its sub-directories.

Perform a case-insensitive search:

The above commands all use the -name parameter which performs a case-sensitive search. To perform a case-insensitive search, replace -name with -iname in the above examples, like so:

find / -iname "filename.php"

Perform a wildcard search:

The wildcard character is *. If you want to find all .php files, for example, use the following command:

find / -iname "*.php"



How to change DNS settings on your local PC

Have you ever been working on a website, changed your DNS settings over to a different server and later needed to access that server again from the old domain name for some reason? Well if you are an active developer, this situation is somewhat common. I'll explain or you can skip the rest of this paragraph to quickly learn now to do it. Let's say you own the domain name and a web server with an IP address of Now assume you have a WordPress blog on that server that you had to move to another server with IP Let's say you already changed the DNS settings for to point to the new server with IP but you need to go back to the original WordPress site on the other server with an IP of What do you do? We all know a WordPress site won't function properly with just the IP address, so that is out. What you need to do is repoint to in order to access that WordPress site again. What a PITA, right? Well read on and I'll show you a fast and easy way to make the site on the original server work with even after you've pointed it to another IP address or web server! It's as simply as controlling a local host file on your local PC to make route to even though the internet routes it to! Here's how:

Using hosts file to override DNS settings for your PC

A lot of people don't realize that when you make a request to the Internet using your local computer it first checks a local copy of the hosts file for an entry and only if one isn’t present it goes out to the Internet DNS servers. Therefore there's an opportunity present for you to redirect only for your own PC if you wanted to! Here are the easy steps:

  1. Open file explorer and navigate to C:\Windows\System32\drivers\etc.
  2. Open the file named "hosts" in notepad or another text editor that could be used as a code editor such as Notepad++, which is what I use.
  3. Now simply add a line to the end of the hosts file that contains the IP address of the server you want to route the domain name too followed by a space and then the domain name you want to reroute. So in our example scenario above, you would enter a new line that reads simply:
  4. Save the hosts file and open your browser and navigate to the domain which in our example was Note that there is a difference between and, so if you want it to work with www, you have to add another entry for

If you're using Notepad++ or similar as I was, you'll need to open it in administrator mode in order to be able to save the hosts file. Good luck! That's all there is to it.

How to change local DNS settings on a Mac

If you're on a Mac, the instructions are basically the same but do this instead:

From the terminal, type:

nano /private/etc/hosts
and then add the IP and domain name as described above, so the only real difference between Mac and a PC when it comes to changing DNS settings is that you will use a different editor and the hosts file is located in different places.



How to Use IPTables

What is iptables?

iptables is a fairly flexible firewall system developed for Linux/Unix operating systems and used commonly for web server administrators to block access to servers by IP address or groups of IP addresses. It can also be used to white-list IP addresses as well. It is a command line tool that allows server administrators to enter simply one line commands to add, edit or delete rules for accessing the web server from the outside world.

Understanding iptables Infrastructure

Understanding the infrastructure of iptables in an important component to learning how to use iptables. Basically there are tables, chains and rules. Tables contain chains and chains contain rules. Here is a simple graphic to illustrate my point:


There are four default tables in iptables and you can add others if you want to get deep into config options. However, I recommend using the default tables to keep things simple. In fact, the filter table is the only one we will be messing with for now. The four default tables are filter, nat, mangle and raw.

  • Filter Table - default table for iptables. If you do not define a table, you’ll be using the filter table. The filter table has the following built-in chains:
    1. Input Chain - handles incoming connections.
    2. Output Chain - handles outgoing connections.
    3. Forward Chain - handles routing of connections like a router.
  • Nat Table - Consists of prerouting, postrouting and output chains. The prerouting chain helps translate destination ip address of the packets to match the routing on the local server. The postrouting chain translates packets as they leave the system and alters packets after routing. The output chain is NAT(Network Address Translation) for locally generated packets on the firewall.
  • Mangle Table - for specialized packet alteration. We will leave this table alone for now as it it outside the scope of this tutorial, but just know it is there.
  • Raw Table - for configuration exemptions. Raw table has a prerouting chain and an output chain.

Chain? WTF does my server need Chains for? Is it winter already?

When using iptables, there are basically three types of chains that we are mainly interested in. They are input chains, output chains and forward chains, the three chains from the filter table described above.

  • Input Chain - used to control the behavior of incoming connections. For example, if a user attempts to SSH into your server, iptables will attempt to match the IP address and port to a rule in the input chain.
  • Output Chain - used with outgoing connections. For example, if you try to ping, iptables will check its output chain to see what the rules are regarding ping and before making a decision to allow or deny the attempt to connect.
  • Forward Chain - used for incoming connections that aren’t delivered locally. It is something like a router where data is always being sent to it but is not destined for the actual router. Data is forwarded to its target. Unless you’re doing some type of routing or NATing  that requires forwarding, you probably won't use a forward chain much if at all.

Understanding iptables Commands

In order to use iptables in Linux, you need to know the basic commands, so I'll go over some of the more common iptables commands here for your learning pleasure!

Note that after you make any change, it is important to save iptables with the following command on Debian/Ubuntu servers:


or in some cases


The save command is a little different for other servers, so take note of the one that applies to your server as noted below:

  • Centos / Redhat: service iptables save or sudo service iptables save if you are not root user.
  • If that didn't work, try:  /etc/init.d/iptables save with and without sudo first.

If you don't save after a change by typing the above at your command prompt and hitting enter, you will most likely lose your changes and/or they will never take effect.

iptables Command to Block a Single Simple IP address

If you wish to simply block an IP such as from accessing your server in any way and from any port, type this at your command prompt and press enter, then save:

iptables -A INPUT -s -j DROP

Whenever possible, always test to be sure your iptables rules work after adding then to be safe. Be sure to save using the appropriate iptables save command as mentioned above after you successfully enter your new rule.

Blocking all IP addresses but your own with iptables

If your server is getting throttled and you want to lock it down immediately or you are simply under construction and don't want anyone but you to be able to access your server, here is how you can block all IP addresses from accessing your server and white-list just one or more IP addresses that will be able to access your server:

iptables -A INPUT -s -j ACCEPT
iptables -A OUTPUT -d -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP

First, you should flush your current rules(see below). Then simply replace with your own IP address in the commands above and enter each of the four commands one at a time from the command line, pressing enter after each, then save iptables.

Flushing iptables rules

To get rid of all active rules in iptables, enter the following command at the Linux command prompt:

iptables -F

Deleting Single iptables Rules

If you entered one or more iptables rules you want to delete without deleting the entire configuration, here is how to do it:

  1. List numbered rules using this command: sudo iptables -L INPUT -n --line-numbers
  2. To delete the first rule enter: sudo iptables -D INPUT 1(where 1 is the line number you want to delete)
  3. Confirm deletion took place by running the first command again and verify the rule is no longer present: sudo iptables -L INPUT -n --line-numbers
  4. Save iptables to be safe: sudo iptables-save


Restrict Number of Connections Per IP

Use connlimit to place restrictions on the number of connections allowed per IP address. To allow 4 ssh connections per client host, enter:
# iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 4 -j REJECT

Set HTTP requests to 20:
# iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j DROP

  1. --connlimit-above 3 : Match if the number of existing connections is above 3.
  2. --connlimit-mask 24 : Group hosts using the prefix length. For IPv4, this must be a number between (including) 0 and 32.


What is this nonsense after the slash in iptables ip addresses?

This is what I need to touch on before we go much further because you've no doubt seen existing rules in your iptables with IP addresses listed similar to:

...and have surely wondered why there is a slash followed by a number after the ip addresses listed in your iptables rules. Well I'll explain as best as I can in the next section as it is a little complicated to explain...

Knowing how to read and write more complex iptables rules with CIDR notation.

Learning to write iptables rules can get very frustrating if you don't understand how the notation works. CIDR, Classless Inter Domain Routing notation, is often confused with network masks which are similar but not the same. I will offer my best explanation of CIDR notation here which I've gathered from several different sources to put together an explanation I feel comfortable with:

Imagine an IP address something like xxx.yyy.zzz.www/N, where N is the number of bits from 0 to 32. Each of the other numbers represents one byte out of the 4 bytes that make up an IP address. N says how many BITS of those 4 bytes matter. So any address that looks like 10.X.Y.Z/8 refers to ANY IP starting with "10.": 8 bits = 1 byte, meaning everything after the first byte is ignored. The convention is to use zeroes in the ignored positions, so the canonical name for that subnet is Most of the time, N is a multiple of 8, so it says to ignore a certain number of bytes.

Once in a while, you'll see something other than that, like a /29. This means that PART of one of the bytes is ignored. For simplicity's sake however, we will stick to multiples of 8 in this guide.

It's also important to note that if the N is omitted, then it's usually assumed to be 32, i.e. a single IP address specification.

So, taking what I've just explained above regarding CIDR notation, Here are some general examples of how netmasks work in conjunction with iptables rules:  - A CIDR of 8 bits means that only 1 of 4 possible bytes of the IP address is noted as represented by the "10" here. so this would cover the IP range from to In other words any IP address starting with "10.". - A CIDR of 16 means that 2 of 4 possible bytes of the IP address are noted as represented here by "100.50.". In this case, a range from to is covered. - A CIDR of 24 means that 3 of the 4 IP address bytes are noted as seen here with "92.50.8." This time a range from to is represented.

Those should be the three most common types of CIDR notations. Following the above pattern of incrementing the number of bits by 8, the next logical example would be something like While that is a perfectly good notation and will work, it is also moot because 32 bits would represent the entire IP address, so you might as well enter it without the CIDR notation(with no slash and number after the IP).  In iptables rules, means the exact same thing as simply putting

What do Bytes and Bits have to do with IP Addresses?

Good question, glad I asked myself! To properly understand how CIDR notation works you have to understand the math behind it. A Byte is made up of 8 bits(that's why we increment by 8 in our previous examples). An IP address is made up of 4 Bytes or 32 Bits(4x8=32).

As you probably know, an IP address is made of of four numbers separated by dots or periods(.) like this: N.N.N.N where N can be any number from 0 to 255. This raised a question in my mind: In an IP address byte, how does a range from 0 to 255 have 8 bits? Well my question just goes to show I don't fully understand how Bytes and Bits correspond with numbers because I googled around and discovered that indeed Eight binary bits can represent any whole number from zero to 255, so the segments of a dotted decimal address are decimal numbers with a range from 0 to 255.  I think it's enough for now to understand that it is correct without getting into exactly how Bytes and Bits work with IP addresses because I don't want this tutorial to confuse you even more. Let's just know for now that 1 Byte = 8 Bits and that a Byte can be any number from 0 to 255 in an IP address which is made up of 4 Bytes and/or 32 Bits. If anyone would like to explain how this works in more detail, feel free to make a comment on this post and I'll make sure it gets published.