All posts by ian11

Getting Unterminated String Literal Error When Using Newlines In JavaScript Variable

Nothing like a good Unterminated String Literal Error to fog up your day huh? Well I found a neat little trick to squash this nasty bug with JavaScript today!

The Problem

The problem in my case is that I wanted to place the contents of a PHP variable, filled with data from a database table, into a JavaScript variable which I thought could be easily done like in  the following JavaScript code example:

var sc = "<?php echo $email_content; ?>";

WRONG! I discovered that when the PHP variable holds text with newline characters in it, like you'll often encounter when retrieving data from a database or from a textarea, or even a file, JavaScript throws the nasty old "Unterminated string literal" error! I've learned to hate this general JavaScript error over the years, but today, I stumbled upon a small, yet useful, trick that makes this error go away in cases like this.

The Solution:

Believe it or not, the solution is as simply as replacing quotes in the JavaScript code with backticks. If you don't know what a backtick is, read on, otherwise your JavaScript code should look like this after replacing quotes with backticks:

var sc = `<?php echo $email_content; ?>`;

What is a Backtick?

A backtick is the little character that looks like a slanted single quotation mark that normally calls the key above the tab key home on a normal English keyboard. Otherwise known as the Marigold key, grave accent or backquote, the character is a tricky one simply because no one knows what to call it. However, in the land of computer programming, it is commonly referred to as the backtick character, so that's what we'll call it. Cool? Okay!

 

WordPress Custom Post Type Meta Box with Form Validation

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

add_car

What You'll Learn

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

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

Here are the steps you'll follow:

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

Step One - Start a new plugin

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

<?php
/**
 * Plugin Name: Cars
 * Plugin URI: http://jafty.com/blog/crash-course-on-wordpress-plugin-development/
 * Description: A custom Car plugin developed for WordPress car websites.
 * Version: 0.0.1
 * Author: Ian L. of Jafty.com
 * Author URI: http://jafty.com
 * License: GPL2
 */

?>

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

Step Two - Add a Custom Post Type

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

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

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

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

Step Three - Add simple Meta Box to Our Plugin

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

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

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

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

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

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

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

}//end create_car_metabox function to create car tabs

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

Step Four - Add Error Handling Functions to Your Plugin:

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

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

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

Step Five - Save Meta Box Data in WordPress

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

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

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

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

Screen Shots:

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

errors

Below is what the add new Car screen looks like:

add_car

Summary:

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

Sorting Multi-Dimensional Associative Arrays in PHP

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

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

db

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

Fetching Data From WordPress Database to Build an Associative Array

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

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

Building a Multi-Dimensional Associative Array in PHP

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

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

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

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

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

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

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

<?php

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

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

?>

Sum It Up!

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

http://php.net/manual/en/array.sorting.php

Developer’s Guide to Working With Contact Form 7

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

How to retrieve information submitted in Contact Form 7 Forms

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

Why Retrieve Data from Contact Form 7 Forms?

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

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

Retrieving Data From CF7 Forms

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

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

}

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

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

function process_contact_form_data( $contact_form ){

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

}//end process_contact_form_data function

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

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

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

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

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

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

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

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

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

 

How to Send SMS Text Messages From PHP

In this PHP tutorial, I'll be showing you how to send text messages to cell phones from a website or app using PHP with a simple HTML form to collect the data. The only drawback to sending messages from PHP is that you typically need to know the receiving party's cell phone carrier in addition to their phone number. The only existing method of getting around having to know the person's cell phone carrier is to use a paid service to send SMS messages such as an SMSC or Short Message Service Center. One provider of SMS services is https://www.twilio.com/.

What are your SMS messaging needs?

This is an important question you should answer before proceeding because if you need to be able to send text messages  with just a phone number and the message content, then you'll need an SMSC like Twilio, otherwise, if you don't mind making the user enter their Cell Phone Carrier name in addition to their phone number in a form to send a text message to them, then the free solution I'm about to show you will work fine for you.

Sending Text Messages From PHP

The basic high level steps to building an application to send out text messages from a web form are as follows:

  1. Built an HTML form that submits to a PHP processing script and that collects the receiving party's phone number, cell carrier name and the text message content.
  2. Create the PHP processing script to receive and process the information gathered in the form and send out the text message, using an email service, to the receiving party.

The entire process in it's simplest form is outlined below:

Write the HTML form. I created a folder named "SMS" and put a new PHP file named "index.php" inside the folder, then added the HTML for the text messaging form as you see here:

<form method="post" action="">
Phone No.: <input type="text" id="ph" name="ph" value="1231231234" /><br />
<br />
Carrier: <select id="ca" name="ca">
<option value="">[Select a Provider]</option><option value="">--Popular Providers--</option><option value="alltel">Alltel Wireless</option>
<option value="@att.txt.net">AT&amp;T</option>
<option value="@myboostmobile.com">Boost Mobile</option>
<option value="@sms.mycricket.com">Cricket</option>
<option value="@messaging.nextel.com">Nextel</option>
<option value="@messaging.sprintpcs.com">Sprint</option>
<option value="@tmomail.net">T-Mobile / Voice Stream</option>
<option value="@tmomail.net">TracFone</option>
<option value="@vtext.com">Verizon Wireless</option>
</select>
<br />
<br />
<textarea rows="5" cols="65" id="msg" name="msg"></textarea>
<br />
<input type="submit" id="sbtsms" name="sbtsms" value="Send Text!" /><br />

</form>

Above is your HTML form, next write some PHP code to process the above form like so:

<?php
if(isset($_POST['ca'])){//if info was submitted, send sms msg:
$ca='';
$ph = $_POST['ph'];
$ca = $_POST['ca'];
$msg = $_POST['msg'];

//if carrier is still blank, set the default carrier(verizon is the most used carrier in the U.S., so....:
if($ca=='')$ca='@vtext.com';

//combine the phone number and the carrier to make the email address to send SMS messages to:
$send_to = $ph.$ca;
echo "Attempting to reach $ph via $ca carrier.....<br />";
echo "Sending Message to $send_to:<br />$msg<hr />";
$sent_sms = mail($send_to, '', $msg);
if($sent_sms){
echo "<h2 style='color:lime'>Message Sent!</h2>";
}else{
echo "<h3 style='color:red'>Oops! Something went wrong, try again later. Make sure you selected the right carrier and phone number.</h3>";
}
}//end if info was submitted, send msg
?>

...the above code goes right after the </form> tag from above, then save the file as sms.php and upload it to your server and try to send yourself a message. If you use a different carrier than the ones provided in the code, you may need to add some options. A complete list of carriers can be downloaded online from https://davidwalsh.name/demo/SMS-Carriers.pdf

Here is a ready to copy and paste version you can simply copy all the below code into a file and save it as a .php file and it should work out of the box for the carriers listed in the provided dropdown:

<!DOCTYPE html>
<html>
<head>
<title>SMS via PHP</title>
</head>
<body>
<h1>Send Text Messages Online for Free!</h1>
<p>Yes, you can send SMS or Text messages online for free using PHP and sendmail. You simply have to provide all of the information requested in the below form and click the send text button to deliver it to the phone number you entered. You must know the receiving party's phone carrier for this to work however.</p><p>Tip: you can usually get the carrier of someone's phone by looking at an email they have sent you and reading the part after the @ symbol in the "From" email in the header of the email you received.</p>

<form method="post" action="">
Phone No.: <input type="text" id="ph" name="ph" value="1231231234" /><br />
<br />
Carrier: <select id="ca" name="ca">
<option value="">[Select a Provider]</option><option value="">--Popular Providers--</option><option value="alltel">Alltel Wireless</option>
<option value="@att.txt.net">AT&amp;T</option>
<option value="@myboostmobile.com">Boost Mobile</option>
<option value="@sms.mycricket.com">Cricket</option>
<option value="@messaging.nextel.com">Nextel</option>
<option value="@messaging.sprintpcs.com">Sprint</option>
<option value="@tmomail.net">T-Mobile / Voice Stream</option>
<option value="@tmomail.net">TracFone</option>
<option value="@vtext.com">Verizon Wireless</option>
</select>
<br />
<br />
<textarea rows="5" cols="65" id="msg" name="msg"></textarea>
<br />
<input type="submit" id="sbtsms" name="sbtsms" value="Send Text!" /><br />

</form>

<?php
if(isset($_POST['ca'])){//if info was submitted, send sms msg:
$ca='';
$ph = $_POST['ph'];
$ca = $_POST['ca'];
$msg = $_POST['msg'];

//if carrier is still blank, set the default carrier(verizon is the most used carrier in the U.S., so....:
if($ca=='')$ca='@vtext.com';

//combine the phone number and the carrier to make the email address to send SMS messages to:
$send_to = $ph.$ca;
echo "Attempting to reach $ph via $ca carrier.....<br />";
echo "Sending Message to $send_to:<br />$msg<hr />";
$sent_sms = mail($send_to, '', $msg);
if($sent_sms){
    echo "<h2 style='color:lime'>Message Sent!</h2>";
}else{
    echo "<h3 style='color:red'>Oops! Something went wrong, try again later. Make sure you selected the right carrier and phone number.</h3>";
}
}//end if info was submitted, send msg
?>

</body>
</html>

Taking it further

The main drawback to this method is that you have to also know the cell phone carrier, but I've thought of a way to overcome that with a bit of extra coding.  I found this site that takes the phone number in three parameters so for my business line,(234) 650-2011, it would be like this:

http://fonefinder.net/findome.php?npa=234&nxx=650&thoublock=2011

I plan to write a PHP script to resolve the address and scrape the results to get the carrier name. It will be a little complicated because you'll need to get the carrier name and then translate it into the actual email for ea. carrier, but it is definitely possible with some work.

Summary:

That's all there is to it! You can definitely improve upon this version of course as it is just meant to get you started. There is no form authentication and only very limited cell phone carriers listed in the dropdown, but the resource is provided to add more carriers from https://davidwalsh.name/demo/SMS-Carriers.pdf, so feel free to build onto what I've started here and let us know what improvements you've made in a comment so others can learn from it!

 

WordPress Permalinks Not Working

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

Save Permalinks

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

Edit Config File

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

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

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

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

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

      Require all granted

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

        Options Indexes FollowSymLinks MultiViews
        AllowOverride All

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

<Directory /var/www/html/dev.jafty.com/public_html>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
</Directory>
<VirtualHost *:80>
    ServerName dev.jafty.com
    ServerAlias www.dev.jafty.com

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

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

Hope that helps! Good Luck!

 

How to Open and Close Windows with JavaScript from Parent and Child

Today I wasted a couple hours trying to figure out how to close a window that had been opened from a parent page with a button in the child window. I wrote this quick JavaScript tutorial on how to open and close windows from parent and child in hopes that it will help someone else figure it out faster than I did.

To keep it simple, we will use two HTML files in this example and we'll call them open_close_window.html and popup.html where open_close_window.html will be the parent and popup.html will be the child pop up window. open_close_window.html, the parent, will include two JS functions and a button while the child, popup.php will include nothing but a button to close itself. What I found a little odd was that in order to close the child window from within itself, I had to call a function from the parent. Here's how it is done. Below is the full contents of both files:

open_close_window.html content:

<html>
<head>
<script>
var myWin;
function openWin(){
myWin = window.open("popup.html", "myWindow", 'width=600,height=300');
}//end openWin JS function

function closeWin(){
myWin.close();
}//end closeWin JS function
</script>
</head>
<body>
<button type="button" onclick="openWin();">Open Window</button>
</body>
</html>

Notice that I set the var myWin in the first line of the JavaScript code above. It will not work if you do not place the myWin variable in the global scope like this. Also you can not simply name the window in the window.open function call like I thought I could at first, you have to use a variable to reference the window when closing it.

popup.html content:

<html>
<head>
</head>
<body>
<button type="button" onclick="opener.closeWin();">Close Window</button>
</body>
</html>

Summary

I hope you can see how this all works from this simple demonstration. You don't even need to upload the two files to a web server to test them since they are HTML files, simply place both on your desktop and open the parent, open_close_window.html from there and see how you can click the button to open the child window and then click the child's button to close itself by calling a close function in the parent. Odd, but that's how it's done!

How to Clone a MYSQLI Table From Command Line

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

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

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

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

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

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

How to Get Plugin URL Without a Trailing Slash

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

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

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

http://example.com/wp-content/plugins/WP-PW-sync

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

plugins_url parameters:

plugins_url($path, $plugin);

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

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

Default: None

How to Get Plugin URL Including the Trailing Slash

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

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

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

http://example.com/wp-content/plugins/WP-PW-sync/

plugin_dir_url Parameters:

The plugin_dir_url WordPress function only has one parameter:

plugin_dir_url($file);

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

Default: None

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

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

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

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

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

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

/var/www/public_html/wp-content/plugins/your-plugin/

plugin_dir_path function  parameters

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

plugin_dir_path($file);

$file

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

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

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

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

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

/var/www/public_html/wp-content/plugins/your-plugin

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

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

 

 

How to Figure Out Relative Humidity with PHP

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

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

dew point in Fahrenheit: 42.7

temperature in Fahrenheit: 60.1

1) The first step is to convert to Celsius using the following formulas
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

Domain name:

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

NGINX New Site Creation and Server Configurations

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

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

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

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

2) Create the website directory (for example, 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.