All posts by ian11

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
Tc=5.0/9.0*(Tf-32.0)

Tdc=5.0/9.0*(Tdf-32.0)

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

Tc=5.0/9.0*(Tf-32.0)
5.0/9.0*(60.1-32.0)
5.0/9.0*28.1
0.5555555555555556 * 28.1 = 15.61111111111111

dewpoint in Celsius: 5.94
5.0/9.0*(Tdf-32.0)
5.0/9.0*10.7
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=6.11*10.0**(7.5*Tc/(237.7+Tc))
Es=6.11*10.0**(7.5*15.61/(237.7+15.61))
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=6.11*10.0**(7.5*Tdc/(237.7+Tdc))
E=6.11*10.0**(7.5*5.94/(237.7+5.94))
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.

Is Payoneer Better Than PayPal?

PayPal has worked for me for several years and, while they have been mostly good to me, when you do need help, their customer service is practically non-existent. I had a horrible experience with them recently that has made me decide not to use them any longer for a while. I'm almost exclusively a seller and almost never a buyer which makes PayPal a poor choice for me it seems now. I have never had a dispute in all the years I've used PayPal until recently and I can not forgive the way PayPal handled that dispute. If you want to hear my story, read on, if you want to get right to using Payoneer as I suggest if you are a seller of goods or services like me, use this link to sign up for Payoneer now:

https://share.payoneer.com/nav/Z0p1ilVwR6cXc5rK-hfGzOqAEhykGqdX9Q20h_PXFPXbJvtO-8cjY1wD_4Db8uwuUY0QGJmc9EVKLQ-V_ld1OA2

My Experience with PayPal

My bad experience that makes me want to completely stop using PayPal has to do with a former client of mine that filed a dispute after I had to inform them that I had to quit working for them because another client needed me(the other client that needed me has been a client for many years and the client I quit working for was new). When I quit working for the new client, he still owed me roughly $200 in my opinion. He had paid me a deposit of $200 when I started working with him because I always get a deposit to protect me from newer clients. I had completed a total of $400 worth of work before I quit working for him however, so really he still owed me $200. I was going to forgive the money he owed me however, since I had quit because I figured he wouldn't pay it anyway. So, for being a nice guy, the new client rewards me by filing a dispute on PayPal asking me to return $95 to him! I was shocked, but had confidence that PayPal would see it for what it was, an attempt by a client to get his money back even though I had completd the work, Fraud. So I refused to return the money and he escalated his false claim. To my surprise, without doing any investigation what-so-ever, PayPal made a decision in his favor. Okay, so I lost, I could have handled that without closing my account, but the kicker is that they didn't just reward the client the $95 he was asking for, they reversed the entire $200 payment he ad sent me! After losing the dispute, I first tried to call PayPal's "customer support" and was told I would have to wait on hold for over an hour! I waited on hold regardless of the ridiculous amount of hold time, but the call was never answered so I gave up after over an hour of waiting for a human to speak with about my issue. Then I sent them sent an email asking them why and got a computer reply that had absolutely nothing to do with the questions I asked in the email. So obviously, I was getting nowhere and it is clear now that I just got ripped off for $200 by PayPal and my former client. So, hello Payoneer! I'll let you all know how this new payment method works for me. Hopefully better than my experience with PayPal! Again, here's the link for Payoneer if anyone else wants to check them out:

payoneer.com

My experience with Payoneer

So, while I am new to Payoneer, I will post my experiences here so others can benefit from them. First off, if you want or need to get your money immediately(Like you could with a PayPal Credit card if you were lucky enough to be approved), then Payoneer might not be the best service for you. I sent out my first invoice several days ago, on a Thursday to a client I completely trust and that client informed me that he paid the invoice immediately that same day, so the invoice was paid on Thursday. It is now the following Saturday and the invoice is yet to be even marked as paid in my Payoneer account. That kind of worries me. I read in their F.A.Q. that it can take from 3-5 business days, so luck me, it's the weekend! Right? Oh well, so that means it has only been one business day so far and the fifth business day would be next Thursday. I have to say that it it in fact takes that long, I won't be happy with the services at all. On the other hand, it the payment is in my account by Monday or Tuesday, I will be satisfied, not perfectly happy, but barely satisfied. I currently hate PayPal so much that I don't mind waiting a few days to get paid another way. However, a week is too long, so I'll let you all know asap when I can actually get the funds that were sent to me last Thursday. FYI, here's an image from Payoneer's website regarding information about the billing service I used to send my first invoice to my long-time trusted client:

payoneertable

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:
https://www.den4b.com/products/renamer

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

How to Download and Open ReNamer for First Use

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

Use the link https://www.den4b.com/products/renamer 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:

renamerules

 

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 "subdom.jafty.com.".
  • 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 www.example.com or just example.com. 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 "example.com." and name the other "www.example.com.". If you're using a sub domain then name one "sub.example.com." and the other "www.sub.example.com." 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 subdir.jafty.com, but these directions are the same as if I were using just jafty.com instead. First, create the directory /var/www/html/subdir.jafty.com. Then create /var/www/html/subdir.jafty.com/logs and /var/www/html/subdir.jafty.com/public_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 subdir.jafty.com.conf. 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 example.com with your domain or sub-domain):  sudo a2ensite example.com.conf
  5. Reset apache2 with: sudo service apache2 restart

VHOSTS Example File Contents

<Directory /var/www/html/planner.jafty.com/public_html>
    Require all granted
</Directory>
<VirtualHost *:80>
    ServerName planner.jafty.com
    ServerAlias www.planner.jafty.com

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/planner.jafty.com/public_html

    ErrorLog /var/www/html/planner.jafty.com/logs/error.log
    CustomLog /var/www/html/planner.jafty.com/logs/access.log combined
</VirtualHost>

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 Jafty.com for a fast, free quote by email or Skype. My email is linian11@yahoo.com and my Skype name is ianlin11. Or use the contact link on this site.

Summary

That is how you do it!

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:    http://jafty.com/twenty-seventeen-child/
 Description:  Twenty Seventeen Child Theme
 Author:       Ian L. of Jafty.com
 Author URI:   http://jafty.com
 Template:     twentyseventeen
 Version:      1.0.0
 License:      GNU General Public License v2 or later
 License URI:  http://www.gnu.org/licenses/gpl-2.0.html
 Tags:         light, dark, two-columns, right-sidebar, responsive-layout, accessibility-ready
 Text Domain:  twenty-seventeen-child
*/

Functions.php Code

<?php
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 ),
        wp_get_theme()->get('Version')
    );
}
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );
?>

Troubleshooting

  • 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>
<html>
<head>
<meta charset="UTF-8" />
<title>Aria Examples</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<style>
div.topic {
    display: none;
    margin-bottom: 1em;
    padding: .25em;
    border: black thin solid;
    background-color: #EEEEFF;
    width: 40em;
}
</style>
</head>
<body>

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

<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.
</div>

<script>
$(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
   this.bindHandlers();

} // 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.$id.click(function(e) {

      thisObj.toggleRegion();

      e.stopPropagation();
      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
        $(this).focus();

        // update the button label
        thisObj.$id.find('span').html('Hide');

      }
      else { // region is expanded

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

        // update the button label
        thisObj.$id.find('span').html('Show');
      }
    });

} // end toggleRegion()
</script>
</body>
</html>

Thank you oaa-accessibility.org 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 http://oaa-accessibility.org/

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.

Summary

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 linian11@yahoo.com 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, Jafty.com with no added custom fields:

nav1

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:

nav2

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:

iconnav

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...

THE CODE:

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:

<?php
/**
* Plugin Name: Jafty Top Nav
* Plugin URI: http://jafty.com/
* 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 Jafty.com
* Author URI: http://jafty.com
* 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 'http://jafty.com/wp-content/plugins/jafty-top-nav-plugin/menu-item-custom-fields.php';
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:

<?php
/**
* 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 ) {
return;
}

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 )
) ?>
</p>
<?php
endforeach;
}

/**
* 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;
}
}
Jafty_Custom_Nav_Fields::init();
?>

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:

<?php

/**
 * 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:

<?php

/**
 * 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!
            '/(?=<(fieldset|p)[^>]+class="[^"]*field-move)/',
            $this->get_fields( $item, $depth, $args ),
            $item_output
        );
    }

    /**
     * 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 ) {
        ob_start();

        /**
         * 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 -->

Summary

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.

Get IP Address from Domain Name

Here is a simple little tool written in PHP that will return the IP address of any given domain name or if there are more than one, a list of IP addresses will be returned.

 

Get Domain Name's IP Address

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.


Get Domain Name's IP Address

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.

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, your_new_site.com):

mkdir -p /var/www/your_new_site.com/public_html
mkdir -p /var/www/your_new_site.com/logs

3) Change the ownership of the directory to the web user:
chown -R www-data:www-data /var/www/your_new_site.com/public_html
chown -R www-data:www-data /var/www/your_new_site.com/logs

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/existing_site.com /etc/nginx/sites-available/your_new_site.com

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

nano /etc/nginx/sites-available/your_new_site.com
Edit the line that reads: root /var/www/existing_site.com/public_html 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/sandiboudreau.com /etc/nginx/sites-enabled/

7) Restart NGINX:

service nginx restart

9) Create the database and user.

mysql -u root -p
your_password
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)
quit

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 linian11@yahoo.com

Summary

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! linian11@yahoo.com is my email.

PHP Function explode

The PHP explode function is one of the most used PHP functions, at least by me. It is used to turn a string into an array. Let's say you had the following string:

$str = "Pizza, Pork, Ham, Sub, Chicken, Lamb, Rice, Noodles";

You can very easily turn such a string into an array using the PHP explode function like this:

$foods = explode(",", $str);

Now you have the equivalent of this:

$foods = array('Pizza', 'Pork', 'Ham', 'Sub', 'Chicken', 'Lamb', 'Rice', 'Noodles');

Here is a complete PHP example that demonstrates the use of explode:

$str = "Pizza, Pork, Ham, Sub, Chicken, Lamb, Rice, Noodles";

$foods = explode(",", $str);

foreach($foods as $food){

echo $food."<br />";

}

The above example simply uses explode to break the $str string into the $foods array by splitting the string up by the commas.

Arguments

The PHP explode function takes two arguments:

explode('split-by', $string);

  • split-by - can be any value in $string that you want to separate the string into an array by.
  • $string - is the string you want to turn into an array.

Summary

This post should give you a good idea of how to use the explode function. If not, feel free to post your comments on this post and I'll be happy to explain. Also, feel free to publish your own example code that users explode in the comments.

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:

<?php

//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'])) {
        return;
    }

    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' => ''),

or

'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: https://github.com/jonbish/remove-slug-from-custom-post-type. The code below is code I wrote based on that link but updated for nginx servers:

<?php
class JAFTY_CPT_SlugKiller{
    
    static $_s = null;
    private $htaccess_tag = 'SLUG KILLER REMOVE SLUG RULES';
    
    public function __construct() {
        $this->rewrite_rules();
        
        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();
        $jafty_o->rewrite_rules(true);    
        //$jafty_o->add_rules_htaccess();
    }

    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) {
                $this->rewrite_rules(true);
                //$this->add_rules_htaccess();
                flush_rewrite_rules();
            }
        }
    }
    
    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)
            flush_rewrite_rules(false);
    }
    
    
    private function add_rules_htaccess() {
        global $wp_post_types;
        $suffix = get_option('jafty_permalink_customtype_suffix');
        $write = array();
        $htaccess_filename = ABSPATH . '/.htaccess';
        if(is_readable($htaccess_filename)){
            $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;
            }
            fclose($htaccess);
        }else{
            add_action('admin_notices', array(&$this, 'compatibility_notice'));
            return;
        }
        
        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') );
//END CODE TO ENABLE NO SLUG FOR team_member CPT

?>

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.

Get the Nth Weekday of Any Month and Year with JavaScript

In today's challenge for a client of mine, I had to write a JavaScript function that returns the Nth Weekday of any given month and year. For example it can tell you what the 1st Monday is in December, 2017. It can do past, present and future so if you needed to know the 4th Friday in August of 1910, this function can tell you. If you need to know what the second Sunday of January 2050 is going to be, this JavaScript function will tell you!

Without any further time wasting, here is the JavaScript code that can determine the first, second, third, fourth or even fifth Monday, Tuesday, Wednesday, Thursday, Friday, Saturday or Sunday for any month and year you pass it:

JavaScript Code Returns Nth Weekday for any Given Month & Year:

<script>
/* JavaScript getMonthlyWeekday Function:
 * Written by Ian L. of Jafty.com
 *
 * Description:
 * Gets Nth weekday for given month/year. For example, it can give you the date of the first monday in January, 2017 or it could give you the third Friday of June, 1999. Can get up to the fifth weekday of any given month, but will return FALSE if there is no fifth day in the given month/year.
 *
 *
 * Parameters:
 *    n = 1-5 for first, second, third, fourth or fifth weekday of the month
 *    d = full spelled out weekday Monday-Friday
 *    m = Full spelled out month like June
 *    y = Four digit representation of the year like 2017
 *
 * Return Values:
 * returns 1-31 for the date of the queried month/year that the nth weekday falls on.
 * returns false if there isn't an nth weekday in the queried month/year
*/
function getMonthlyWeekday(n,d,m,y){
var targetDay, curDay=0, i=1, seekDay;
    if(d=="Sunday") seekDay = 0;
    if(d=="Monday") seekDay = 1;
    if(d=="Tuesday") seekDay = 2;
    if(d=="Wednesday") seekDay = 3;
    if(d=="Thursday") seekDay = 4;
    if(d=="Friday") seekDay = 5;
    if(d=="Saturday") seekDay = 6;
while(curDay < n && i < 31){
    targetDay = new Date(i++ + " "+m+" "+y);
    if(targetDay.getDay()==seekDay) curDay++;
}
if(curDay==n){
targetDay = targetDay.getDate();
return targetDay;
}else{return false;}
}//end getMonthlyWeekday JS function
</script>
<a href="JavaScript:var dy = getMonthlyWeekday(1,'Sunday','March', 2017);alert('1st Sunday in March, 2017 falls on March, '+dy);">Get first sunday in March, 2017</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(2,'Sunday','March', 2017);alert('2nd Sunday in March, 2017 falls on March, '+dy);">Get second sunday in March, 2017</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(5,'Sunday','March', 2017);alert('5th Sunday in March, 2017 falls on March, '+dy);">Get fifth sunday in March, 2017</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(4,'Friday','April', 2017);alert('4th Friday in April, 2017 falls on April, '+dy);">Get 4th Friday in April, 2017</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(5,'Monday','April', 2017);alert('5th Monday in April, 2017 falls on April, '+dy);">Get 5th Monday in April, 2017</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(3,'Wednesday','October', 1995);alert('3rd Wednesday in October, 1995 falls on October, '+dy);">Get 3rd Wednesday in October, 1995</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(4,'Wednesday','October', 1995);alert('4th Wednesday in October, 1995 falls on October, '+dy);">Get 4th Wednesday in October, 1995</a><br />
<a href="JavaScript:var dy = getMonthlyWeekday(4,'Wednesday','May', 1975);alert('4rd Wednesday in May, 1975 falls on May, '+dy);">Get 4th Wednesday in May, 1975</a><br />

Summary

That will do the job! All you have to do is copy and paste the above code in green into a blank text file and name it something like weekdays.html or test.html and open it in any web browser to test the code. Then feel free to alter it to fit your exact needs. Have fun!

 

 

 

Including Responsive Videos in WordPress Posts

I've done a lot of things with WordPress to-date, but one thing I haven't done much with is videos. I was commissioned to build a plugin to embed responsive videos into WordPress posts. Naturally I started trying to figure out how to embed a simple Vimeo video into a post, this post right here in fact. I went to Vimeo.com and got the link for one of the videos my client is using. I am going to post just that plain text link on the next line below:

...and presto-magico! WordPress did most of the work for me! As you can see the video showed up just from me copy and pasting the Vimeo URL in the post! For example, I posted "https:// vimeo.com/ 155235235" without the quotes or spaces. I just added spaces so WordPress wouldn't make it a video like it did above.

Therefore, the only task left to me is to make the videos responsive.

How to make videos responsive in WordPress

The most basic method, which you may want to use if you only need to apply this fix to one or two videos on your site,  is to add a wrapper div to your video url when you insert it int o your blog post like this:

<div class="video-wrap"> VIDEO URL GOES HERE! </div>

Then add the following CSS to your theme's main style sheet, style.css:

.video-wrap{
    position: relative;
    padding-bottom: 56.25%;
    height: 0;
    overflow: hidden;
}
.video-wrap iframe, .video-wrap object, .video-wrap embed, .video-wrap video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

That's all you have to do if you don't mind making manual edits each time you add a video to your blog.

Making a Simple WordPress Plugin to Make Videos Responsive

The logical option to use if you regularly embed videos in your WordPress site, is to create a very simple plugin that hooks into WordPress while it embeds videos and automatically wraps the embed code inside of a div and then applies style to that div to accomplish the same effect we did above without having to make changes each time we add a new video. Here is how:

Add the following code to a new php file and name it whatever you want to call your custom plugin or call it jafty-responsive-video-embedder as I did here:

<?php
/*
Plugin Name: Jafty Responsive Video Embedder
Plugin URI: http://jafty.com

Description: Adds a wrapper div around embedded videos and applies mobile style to them so they are responsive at all times regardless of the surrounding HTML.

Author: Ian L. of Jafty.com
Author URI: http://jafty.com

Version: 1.0.0

License: GNU General Public License v2.0
License URI: http://www.opensource.org/licenses/gpl-license.php
*/

//Code to make Videos more responsive:
function make_video_responsive( $html ) {
    return '<div class="video-wrap">' . $html . '</div>';
}
 
add_filter( 'embed_oembed_html', 'make_video_responsive', 10, 3 );
add_filter( 'video_embed_html', 'make_video_responsive' ); // Jetpack

function add_video_css(){
wp_enqueue_style("videocss", "/wp-content/plugins/outer-gain-engine/video.css");
}

add_action('wp_enqueue_scripts', 'add_video_css');

?>

Then create a file named video.css and copy and paste the follocing CSS code into it:

.video-wrap{
    position: relative;
    padding-bottom: 56.25%;
    height: 0;
    overflow: hidden;
}
.video-wrap iframe, .video-wrap object, .video-wrap embed, .video-wrap video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

Summary

That's all there is to it. A simple, yet handy, plugin or fix for your WordPress videos. Feel free to modify the code to fit your individual needs. Good Luck!

Programmatically Add Page from a WordPress Plugin

In this tutorial, I'll show you how to make your WordPress plugin automatically create a WordPress page when the plugin is activated from wp-admin.

Let's just dive right in to the PHP code this time!

//Add Events page on activation:
function install_events_pg(){
        $new_page_title = 'Events';
        $new_page_content = 'This is your page content that automatically gets inserted into the Events page!';
        $new_page_template = ''; //ex. template-custom.php. Leave blank if you don't want a custom page template.
        //don't change the code below, unless you know what you're doing
        $page_check = get_page_by_title($new_page_title);
        $new_page = array(
                'post_type' => 'page',
                'post_title' => $new_page_title,
                'post_content' => $new_page_content,
                'post_status' => 'publish',
                'post_author' => 1,
        );
        if(!isset($page_check->ID)){
                $new_page_id = wp_insert_post($new_page);
                if(!empty($new_page_template)){
                        update_post_meta($new_page_id, '_wp_page_template', $new_page_template);
                }
        }
}//end install_events_pg function to add page to wp on plugin activation

register_activation_hook(__FILE__, 'install_events_pg');

That's really all there is to it. Of course, you'll want to edit the $new_pg_title to contain the title of your own custom page and you'll want to edit $new_pg_content to contain html elements for your page content, but this will get you started. Just by copy and pasting the above code into your plugin's main file, you will see the "Events" page added when you activate the plugin. If your plugin is already activated, simply deactivate and acti

How to Use jQuery UI Elements In a WordPress Plugin or Theme

Today I found myself once again needing to use jQuery in a new WordPress plugin I am developing for a client. I won't lie, I often dread having to use jQuery within WordPress. It has been getting easier however, especially since WordPress version 3.3.x when they made many of the jQuery UI libraries part of the WordPress core. The trick is knowing that and knowing how to use them! For example I didn't know about the jQuery UI libraries being part of the WP core until recently, so was just hacking my own jQuery into WordPress. The problem with hacking in a jQuery UI or any other jQuery code, is that it will usually break some other jQuery code in WordPress. Therefore I am putting together a quick reference guide on how to include jQuery and jQuery UI scripts in WordPress plugins and themes for my own reference and for other developers who can profit from this information.

First, here is a list of 35 jQueryUI elements already available within WordPress as of version 3.3.x:

Name: Enqueue Value: Dependency:
jQuery UI Core jquery-ui-core jquery
jQuery UI Widget jquery-ui-widget jquery
jQuery UI Accordion jquery-ui-accordion jquery
jQuery UI Autocomplete jquery-ui-autocomplete jquery
jQuery UI Button jquery-ui-button jquery
jQuery UI Datepicker jquery-ui-datepicker jquery
jQuery UI Dialog jquery-ui-dialog jquery
jQuery UI Draggable jquery-ui-draggable jquery
jQuery UI Droppable jquery-ui-droppable jquery
jQuery UI Menu jquery-ui-menu jquery
jQuery UI Mouse jquery-ui-mouse jquery
jQuery UI Position jquery-ui-position jquery
jQuery UI Progressbar jquery-ui-progressbar jquery
jQuery UI Selectable jquery-ui-selectable jquery
jQuery UI Resizable jquery-ui-resizable jquery
jQuery UI Selectmenu jquery-ui-selectmenu jquery
jQuery UI Sortable jquery-ui-sortable jquery
jQuery UI Slider jquery-ui-slider jquery
jQuery UI Spinner jquery-ui-spinner jquery
jQuery UI Tooltips jquery-ui-tooltip jquery
jQuery UI Tabs jquery-ui-tabs jquery
jQuery UI Effects jquery-effects-core jquery
jQuery UI Effects – Blind jquery-effects-blind jquery-effects-core
jQuery UI Effects – Bounce jquery-effects-bounce jquery-effects-core
jQuery UI Effects – Clip jquery-effects-clip jquery-effects-core
jQuery UI Effects – Drop jquery-effects-drop jquery-effects-core
jQuery UI Effects – Explode jquery-effects-explode jquery-effects-core
jQuery UI Effects – Fade jquery-effects-fade jquery-effects-core
jQuery UI Effects – Fold jquery-effects-fold jquery-effects-core
jQuery UI Effects – Highlight jquery-effects-highlight jquery-effects-core
jQuery UI Effects – Pulsate jquery-effects-pulsate jquery-effects-core
jQuery UI Effects – Scale jquery-effects-scale jquery-effects-core
jQuery UI Effects – Shake jquery-effects-shake jquery-effects-core
jQuery UI Effects – Slide jquery-effects-slide jquery-effects-core
jQuery UI Effects – Transfer jquery-effects-transfer jquery-effects-core

As you can see in the above table, the first 22 items in the list only require jQuery as a dependency. For those, you probably will only need to enqueue the value from the "Enqueue Value" column to make use of the library in your plugin or theme. You often will need to enqueue style for the jQuery library separately as well because as far as I know, WordPress doesn't include many of the styles yet. the last dozen or so in the above table all require jquery-effects-core, so to use those, I believe you'll need to enqueue that as well for them to work. For a complete list of other jQuery scripts that are already within the WordPress core, please visit the following codex page:

https://developer.wordpress.org/reference/functions/wp_enqueue_script/

That page also explains usage of the wp-enqueue-script function to  a degree, but not as detailed as my special-use case described here.

How to Enqueue jQuery UI Elements in WordPress Plugin or Theme

Next I'm explaining how to include a jQuery UI library into your own WordPress plugin or theme. If you're making a plugin, the code below will go into your plugin's main file and if you're working on a theme, then place the code below in the theme's functions.php file. In the following code examples, I'll demonstrate how to include both the jQuery UI element and the corresponding CSS file for using a datepicker in both the front-end and admin areas of WordPress. The code would be the same for any of the UI elements in the above table except that you would of course change the valuse to be enqueued for both the core jQuery file and the CSS file from googleapis.com.

PHP Code to use jQuery UI on the WordPress Front-End

function my_datepicker_function(){
//Enqueue date picker UI from WP core:
wp_enqueue_script('jquery-ui-datepicker');
//Enqueue the jQuery UI theme css file from google:
wp_enqueue_style('e2b-admin-ui-css','http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.0/themes/base/jquery-ui.css',false,"1.9.0",false);
}
add_action('wp_enqueue_scripts', 'my_datepicker_function');

How to add PHP Code to Use jQuery UI on the WordPress Admin or Back-End

The PHP code to include the same datepicker UI in a WordPress back-end, admin page is nearly the same. The only difference is the hook we use in the add_action line at the end of the code is different. For front-end use, we used the wp_enqueue_scripts hook, but for admin use, we will use the admin_enqueue_scripts hook instead. That's all folks!

Then simply include your HTML and  script tag wherever you want to use your datepicker in this case like so:

<div class="wrap">
<input type="text" class="datepicker" name="datepicker" value=""/>
</div>

<script>
jQuery(function() {
    jQuery( ".datepicker" ).datepicker({
        dateFormat : "dd-mm-yy"
    });
});
</script>

Summary

the above example code is just for datepicker UI, but can easily be manipulated for any of the jQuery UI elements in the above table, so experiment and find the one that works for you. You will often need to google the jQuery UI element's name and view an online demo of how it is used without WordPress to get exact code and then simply incorporate the above technique into what you learn. I did this with the sortable UI and it worked great. Good luck!

 

How to get Locations in a 50 Mile Radius with Google Maps API v.3

In this post, I will demonstrate how to make getting locations within a given radius simple. In order to make everyone understand, I will break it down into smaller, easy to read steps.

The Distance-Matrix

The key to creating a solution that gets all locations within a given distance radius is to use the Google Maps API Distance-Matrix. Let's examine a simple example request to the Distance-Matrix Json API:

Single Destination URL Example:

https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=44311&destinations=45735&key=Your_API_Key

copy and paste the above URL into a web browser and replace the text, Your_API_Key, with your google Maps V.3 API key. If you don't have an API key yet, they are surprisingly easy to obtain from https://developers.google.com/maps/web-services/

The Response:

The URL above will return a Json response of:

{
   "destination_addresses" : [ "Guysville, OH 45735, USA" ],
   "origin_addresses" : [ "Akron, OH 44311, USA" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "166 mi",
                  "value" : 267653
               },
               "duration" : {
                  "text" : "2 hours 30 mins",
                  "value" : 8989
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}

Notice that I only used zip codes for orgin and destination in my example URL. You can use any acceptable address format instead of just a zip code of you like, but I find that for getting distances, zip codes work quite efficiently. Examples of acceptable addresses include:

  • Cleveland, OH
  • 593 Brown Street, Akron, Ohio
  • 44319
  • Akron, Ohio 4319
  • 593 Brown Street, Akron, Ohio 44311
  • USA
  • Amsterdam

Those are just a few acceptable addresses that could be used for either the destination or orgin parameters in the URL used for an API request to the Distance-Matrix.

 

Multiple Destination URL Example:

One thing that's important to know about the Distance-Matrix API is that there are limits on it's free usage. At the time of writing this post, the limits were 2500 elements per day. A single request may take up several elements however, so be careful. However it is much more practical to include several destination addresses in a single request because it will make your script run significantly quicker. Here is a simple example that will return a response with two destination distances using just zip codes for addresses again:

https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=44311&destinations=45735|44319&key=Your_API_Key

This the json response will include the distances for both zip codes or addresses passed in the URL. Here is the response from the above URL with two destinations:

{
   "destination_addresses" : [ "Guysville, OH 45735, USA", "Akron, OH 44319, USA" ],
   "origin_addresses" : [ "Akron, OH 44311, USA" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "166 mi",
                  "value" : 267653
               },
               "duration" : {
                  "text" : "2 hours 30 mins",
                  "value" : 8989
               },
               "status" : "OK"
            },
            {
               "distance" : {
                  "text" : "8.9 mi",
                  "value" : 14385
               },
               "duration" : {
                  "text" : "14 mins",
                  "value" : 836
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}

Parsing Json data with PHP

The next task is to fetch a response from PHP and parse the Json data in your PHP code. Lets look at a practical example using our first URL example above that has a single zip code as the destination address and also a single zip code for the orgin. Here is the PHP code to make the request, get a Json response and parse the distance from that response:

<?php
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=44311&destinations=45735&key=Your-API-Key";

    //fetch json response from googleapis.com:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $response = json_decode(curl_exec($ch), true);
    //If google responds with a status of OK
    //Extract the distance text:
    if($response['status'] == "OK"){
        $dist = $response['rows'][0]['elements'][0]['distance']['text'];
        echo "<p>Dist: $dist</p>";
    }
?>

Now lets have a look at how we would modify the above code for a request with two destination addresses instead of one:

<?php
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=44311&destinations=45735|44319&key=Your-API-Key";

    //fetch json response from googleapis.com:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $response = json_decode(curl_exec($ch), true);
    //If google responds with a status of OK
    //Extract the distance text:
    if($response['status'] == "OK"){
        $dist = $response['rows'][0]['elements'][0]['distance']['text'];
        echo "<p>Dist: $dist</p>";
        $dist2 = $response['rows'][0]['elements'][1]['distance']['text'];
        echo "<p>Dist2: $dist2</p>";
    }
?>

If you insert your own API key in the above code and run it from your own server, the response would look like this:

Dist: 166 mi

Dist2: 8.9 mi

Notice the difference in the $dist and $dist2 variable values. The key of the elements is different. The first distance is stored in elements[0] while the second is stored in elements[1]. If we had three destinations in the request, the third would be in elements[2] and so on...

How to figure out the values

So, what if you want more than just distance from the returned json element? Lets examine the returned data and figure out how to get it into PHP variables. In the example code above, try placeing this code right after the line that reads "if($response['status'] == "OK"){" and it will show you what the PHP array looks like after the Json response was converted to a PHP object:

        echo "<pre>";
        print_r($response);
        echo "</pre>";

The above code inserted into the last code example would look like:

<?php
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=44311&destinations=45735|44319&key=Your-API-Key";

    //fetch json response from googleapis.com:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $response = json_decode(curl_exec($ch), true);
    //If google responds with a status of OK
    //Extract the distance text:
    if($response['status'] == "OK"){
        echo "<pre>";
        print_r($response);
        echo "</pre>";
        $dist = $response['rows'][0]['elements'][0]['distance']['text'];
        echo "<p>Dist: $dist</p>";
        $dist2 = $response['rows'][0]['elements'][1]['distance']['text'];
        echo "<p>Dist2: $dist2</p>";
    }
?>

Again, replace "Your-API-Key" in the URL variable with your own key and run the code. You should see results like this:

Array
(
    [destination_addresses] => Array
        (
            [0] => Guysville, OH 45735, USA
            [1] => Akron, OH 44319, USA
        )

    [origin_addresses] => Array
        (
            [0] => Akron, OH 44311, USA
        )

    [rows] => Array
        (
            [0] => Array
                (
                    [elements] => Array
                        (
                            [0] => Array
                                (
                                    [distance] => Array
                                        (
                                            [text] => 166 mi
                                            [value] => 267653
                                        )

                                    [duration] => Array
                                        (
                                            [text] => 2 hours 30 mins
                                            [value] => 8989
                                        )

                                    [status] => OK
                                )

                            [1] => Array
                                (
                                    [distance] => Array
                                        (
                                            [text] => 8.9 mi
                                            [value] => 14385
                                        )

                                    [duration] => Array
                                        (
                                            [text] => 14 mins
                                            [value] => 836
                                        )

                                    [status] => OK
                                )

                        )

                )

        )

    [status] => OK
)

Dist: 166 mi

Dist2: 8.9 mi

First you see the array printed out from the response after it's converted from Json to a PHP array, then you see the two distances printed to the screen in the last two lines. Examine the array closely and you can figure out the correct keys to use to pick out specific values from the array in your PHP code.

More info on the Distance-Matrix can be found at https://developers.google.com/maps/documentation/distance-matrix/start

How to Make a Simple Pure JavaScript Popup Window

If you are a minimalist like me, you may appreciate this technique of making a simple JavaScript pop up window with nothing but HTML, CSS and JavaScript. It has no JQuery or other code other than those just mentioned.

See it Live

Here is a live version with just a little extra Style added:

http://jafty.com/pop.html

The Code

Now here is the simple code without much extra CSS style to keep it simple. If you copy and paste this into a blank HTML document, you will get a simple JavaScript working popup window:

<!DOCTYPE html>
<html>
<head>
<title>Pure JavaScript Popup</title>
</head>
<body>

<!--This is the popup code for when the div is clicked:-->
<script>
function iconPop(){
    document.getElementById('popcontent').innerHTML="You may click the X in the lower right corner to close this window or you may click outside of this window to close it as well.";
    document.getElementById('thepopup').style.display="block";
    document.getElementById('blackoutdiv').style.display="block";
}//end iconPop JS function

function iconUnPop(){
    document.getElementById('thepopup').style.display="none";
    document.getElementById('blackoutdiv').style.display="none";
}
</script>
<!--this is the blackout div that blacks out the rest of the page when popup is popped:-->
<div onclick="iconUnPop();" id="blackoutdiv" style="position:absolute; width:100%; height:100%; top:0px; left:0px;background-color:#222;opacity:0.6;z-index:9999;display:none"></div>

<!--this is the popup html:-->
<div id="thepopup" style="position:absolute; width:300px; height:150px; top:150px; left:50%; margin-left:-155px;border: 5px solid orange;background-color:white;z-index:99999;padding:15px;-webkit-border-radius:5px;border-radius:5px;display:none;"><span onclick="iconUnPop();" style="position:absolute;bottom:5px;right:5px;color:red;font-weight:bold;cursor:pointer" title="Close Window!">-X-</span><span id="popcontent"></span></div>
<!--End pop up code when icon's clicked-->

    
    <!--this is the div that when clicked, causes the popup window to appear:-->
    <div onclick="iconPop();" style="position:relative;top:75px;left:50%;margin-left:-170px;width:300px;height:200px;border:5px solid orange;-webkit-border-radius:5px;border-radius:5px;padding:30px;background-color:yellow;color:black">Click this div to open the Pure JavaScript Popup!</div>

</body>
</html>

Summary

That's really all there is to it. If you like the live version better, you can right click on the demo and select "view-source" and copy and paste that code into your own blank HTML document.

How to Do Something Every Nth Iteration in a PHP Loop

If you're a PHP coder, you are sure to come across a scenario from time to time where you have a PHP loop and you need to execute specific code every other time the loop iterates or every four times the loop iterates etc.

Using the Modulus Operator

The key to making something happen every nth time in a loop is the modulus operator or %.

A common scenario where you would need to do something in a loop every fourth or fifth iteration only is when you are printing a series of HTML elements. Let's pretend we have 12 items in an array and we want to print them in groups of four per line. While printing the array you will need to print the <br /> tag every four iterations if you want four items on each line.  The code inside your PHP loop would look like this:

if($i % 4 == 0){echo "<br />";}

Now let's put this to the test with some test code using the above scenario. Below I fill an array with 12 words and print them out in a loop four per line:

<?php
$words = array('one','two','three','four','five','six','seven','eight','nine','ten','eleven','twelve');
$noof = count($words);
$i=0;
for($ii=0;$ii<$noof;$ii++){
    $i++;
    echo $words[$ii];
    echo " ";
    if($i % 4 == 0){echo "<br />";}
}//end for loop
?>

Noticed I used $ii in the for loop and set a second variable, $i for using with the modulus line. This is because $ii will start at zero and we need to start at 1 in this case. The results of the above code would be:

one two three four
five six seven eight
nine ten eleven twelve

Today however, I came across a more complex scenario where I was able to also use the modulus operator to save the day. This time I needed to print items from an array inside of HTML list elements. Lets modify the above scenario using lists instead of line breaks to display the array data:

<?php
$words = array('one','two','three','four','five','six','seven','eight','nine','ten','eleven','twelve');
$noof = count($words);
$i=0;
for($ii=0;$ii<$noof;$ii++){
    $i++;
    if($i % 4 == 1)echo "<ul>";
    echo "<li>";
    echo $words[$ii];
    echo "</li>";
    if($i % 4 == 0)echo "</ul>";
}//end for loop
?>

The output of the above PHP code would be:

  1. one
  2. two
  3. three
  4. four
  1. five
  2. six
  3. seven
  4. eight
  1. nine
  2. ten
  3. eleven
  4. twelve

 

The results were four separate ordered lists  as you can see. But how did we do this? Notice the difference in the modulus operator use for the opening <ol> tag and then for the closing </ol> tag.

The tricky part here is we can't use if($i % 4 == 0) on the opening <ol> tag because if you think about it you don't need <ol> printed on 4,8 and 12 which is what if($i % 4 == 0) would produce. In this case, we need to print an opening <ol> tag on iterations 1,5,9 and 13, so we try something else. Here is how I figured this problem out:

First a simple demo of the modulus operator as we first used it:

<?php
$i=0;
for($ii=0;$ii<20;$ii++){
    $i++;
    if($i % 4 == 0)echo "$i<br />";
}//end for loop
?>

The above code results in:

4
8
12
16
20

Which is fine for printing the end </ol> tags, but will not work for printing the opening <ol> tags as I explained earlier, so I tried this instead:

<?php
$i=0;
for($ii=0;$ii<20;$ii++){
    $i++;
    if($i % 4 == 1)echo "$i<br />";
}//end for loop
?>

This time the above code printed out:

1
5
9
13
17

So, if we used a one instead of a zero like if($i % 4 == 1), then it would execute the code in the if statement on iterations 1,5,9 and 13 just as we need! Just for fun, let's see what happens if we use a two instead of zero this time like if($i % 4 == 2). For example:

<?php
$i=0;
for($ii=0;$ii<20;$ii++){
    $i++;
    if($i % 4 == 2)echo "$i<br />";
}//end for loop
?>

This time the results would be:

2
6
10
14
18

so using a 2 to compare 4 modulus with results in the code executing on iterations 2,6,10....etc, but notice in each example where we use 4 as the first number, all the numbers are increments of 4 and when we use zero as the last number we get 4,8,12.... When we use 1 we get 1,5,9.... Finally if we use 2 we get 2,6,10.... From what we have learned I think it's safe to assume that we we used 3, the results would be 3,7,11,15....and so on.

Summary

I hope this article sheds some light on how to use the Modulus operator with PHP. Feel free to experiment by using other numbers in place of where I used 4 each time too! For example, if you want to do something every 5 times instead, you would use something like if($i % 5 == 0). Have fun with it!

 

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

<?php
/**
* Plugin Name: Jafty Top Nav Plugin
* Plugin URI: http://jafty.com/blog/?p=9813
* Description: A Plugin that adds a custom top navigation menu to WordPress.
* Version: 1.0
* Author: Ian L. of Jafty.com
* Author URI: http://jafty.com
* License: GPL2
*/

Register a New Menu Location with WordPress

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

<?php
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.

menuLOC

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' ) ); ?>
    </nav>
  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:
    get_header();
    or you may have something like this instead:
    get_template_part('templates/header.php');
    Regardless which you have, replace the line with:
    get_header('jafty');
    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 Stripe.com, 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 stripe.com 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:

menuLOC2

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:

menustructure

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:

<?php
      $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:

<?php
$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, http://dev.outergain.com/site-settings/
ID: 49, Jafty Interactive, 47, http://jafty.com
ID: 50, Jafty Blog, 47, http://jafty.com/blog
ID: 48, Hello world!, 0, http://dev.outergain.com/2016/12/30/hello-world/
ID: 51, Yahoo Search, 48, http://yahoo.com
ID: 52, Google Search, 48, http://google.com

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 stripe.com-like 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 Stripe.com. 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: http://jafty.com/nav_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:

postemp

Summary:

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!