Category Archives: WooCommerce

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:

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

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

function my_datepicker_function(){
//Enqueue date picker UI from WP core:
//Enqueue the jQuery UI theme css file from google:
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=""/>

jQuery(function() {
    jQuery( ".datepicker" ).datepicker({
        dateFormat : "dd-mm-yy"


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 add Custom Admin Meta Boxes to a WordPress Custom Post Type

I decided to write this detailed tutorial on how to add custom field meta boxes to the WordPress admin mostly because I couldn't find a decent description of how to do it anywhere online. Hopefully this will help others having trouble trying to learn how to add admin meta boxes with custom fields for a custom post type in WordPress. It is an essential step to learning WordPress plugin development.

Let's dive in and learn some code because I believe that is the quickest and easiest way to learn this advanced WordPress method. I say it is an advanced subject because it is a little complex for beginners. If you are not sure how to start your own plugin yet in WordPress, then this topic may be too advanced for you. You should at least learn how to make a very basic WordPress plugin first, so feel free to read one of my more basic WordPress plugin tutorials first.

First of all, I'll show you how to add a single meta box with a single field in it. It is also important to know that you can have more than one field inside a single meta box. It is equally important to know that you can have more than one meta box. Each meta box can have one or more fields in them. It just depends on your individual needs. Below is the basic code for how to add a custom post type with a custom field inside of an admin meta box. I'll also include a basic plugin heading so you may follow along and create a working example to work from:

Adding a Custom Post Type to WordPress Plugin

 * Plugin Name: Jafty Metabox Example Plugin
 * Plugin URI:
 * Description: A Plugin that adds metaboxes to your WordPress blog or site.
 * Version: 1.0
 * Author: Ian L. of
 * Author URI:
 * License: GPL2

 //Add new Custom Post Type named videos:
add_action('init', 'create_video_posttype');
function create_video_posttype(){
            'labels' => array(
            'name' => __('Videos'),
            'singular_name' => __('Video')
        'public' => true,
        'has_archive' => true,
        'rewrite' => array('slug' => 'video'),
}//end create_video_posttype function


Okay, now start a .php file and add the above code in green to the start of it. Name the file "jafty-metabox-example-plugin.php" and save it. Please NOTE: it is important to go into wp-admin/settings/permalinks and re-save those settings after activating a plugin with a custom post type or after adding a custom post type to a plugin. If you do not do this, the custom post type posts will not show up on the front end of your blog.

At this point, you should be able to upload the jafty-metabox-example-plugin.php file to your WordPress site's plugins folder and activate it. If it works, you'll see a new "Video" option in the left navigation menu of wp-admin as in the following photo:


Add a Metabox with a Custom Field to your CPT

Now here is the code to add to the end of the file you started above(just before the closing PHP tag) that will add a meta-box with a custom field inside of it to your plugin. It adds a field to the wp-admin edit screen for the videos CPT(custom post type):

//Add custom admin Meta Boxes:
add_action('add_meta_boxes', 'add_ians_metaboxes');
function add_ians_metaboxes(){
//add meta box for Video type and description:
add_meta_box('meta_box_html_id', 'Video Details', 'video_details_function', 'videos', 'normal', 'high');

//##################### Video Details Metabox: ################
function video_details_function() {
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__)) . '" />';

//Get video description data if its already been entered
$video_desc = get_post_meta($post->ID, '_video_desc', true);
//Start video Description text field HTML:
Video Description:
<input type="text" name="video_desc" value="<?php echo $video_desc; ?>" class="widefat" />
}//end video_details_function

Save the "jafty-metabox-example-plugin.php" file and update it on your site and click on the "Video" link in wp-admin and then click on "Add New" to see the add/edit screen for your new CPT. You will notice your  custom meta-box with the heading of "Video Details". You will also notice the meta-box contains a custom field named "Video Description". You can see both near the bottom of the photo below:


Saving Custom Field Data

Your not quite done however. While the code above will display the metaboxes, it does not save the data as I soon discovered. To save the data, you'll need to add this code directly after your video_details callback function:

//hook into save_post to save the meta box data:
add_action ('save_post', 'save_video_desc');

function save_video_desc($post_id) {
//verify the metadata is set
     if (isset( $_POST['video_desc'])) {
     //save the metadata
     update_post_meta ($post_id, '_video_desc', strip_tags($_POST['video_desc']));


 Adding Multiple Meta-Boxes and Custom Fields

Next I'll show you what out final plugin file would look like if we were to add another custom field to our meta-box and then another meta-box with yet another custom field inside of it. This way you can see how more than one meta-box is added and also how to add more than one field inside of a single meta-box. Here is the complete plugin code containing a total of two meta-boxes and three total custom fields:

* Plugin Name: Jafty Metabox Example Plugin
* Plugin URI:
* Description: A Plugin that adds metaboxes to your WordPress blog or site.
* Version: 1.0
* Author: Ian L. of
* Author URI:
* License: GPL2

//Add new Custom Post Type named videos:
add_action('init', 'create_video_posttype');
function create_video_posttype(){
'labels' => array(
'name' => __('Videos'),
'singular_name' => __('Video')
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'video'),
}//end create_video_posttype function

//Add custom admin Meta Boxes:
add_action('add_meta_boxes', 'add_ians_metaboxes');
function add_ians_metaboxes(){
//add the first meta box for Video type and description:
add_meta_box('meta_box_html_id', 'Video Details', 'video_details_function', 'videos', 'normal', 'high');
//add a second meta box for Video Rating
add_meta_box('meta_box_html_id2', 'Video Rating', 'video_rating_function', 'videos', 'normal', 'high');
//################## Video Details Metabox: ####################
function video_details_function() {
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__)) . '" />';

//Get the video type  if its already been entered
$video_type = get_post_meta($post->ID, '_video_type', true);
// Get the video description if its already been entered
$video_desc = get_post_meta($post->ID, '_video_desc', true);

//Start type select field HTML:
Video Type: <select name="video_type">
<option value="DVD"<?php if($video_type=="DVD")echo " selected";?>>DVD<option>
<option value="Blueray"<?php if($video_type=="Blueray")echo " selected";?>>Blueray<option>
</select><br />
// Start video description field HTML:
Video Description:
<input type="text" name="_location" value="<?php echo $video_desc; ?>" class="widefat" />
}//end video_details_function
//##################### Video Rating Metabox: ###################
function video_rating_function() {
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__)) . '" />';

//Get the start_month data if its already been entered
$video_rating = get_post_meta($post->ID, '_video_rating', true);

//Start type select field HTML:
Video Type: <select name="_video_rating">
<option value="R"<?php if($video_rating=="R")echo " selected";?>>R<option>
<option value="PG"<?php if($video_rating=="PG")echo " selected";?>>PG<option>
</select><br />
}//end video_rating_function

//add your save data hook and function to save all fields here:

//hook into save_post to save the meta box data:
add_action ('save_post', 'save_video_data');

function save_video_data($post_id) {
//verify the metadata is set
     if (isset( $_POST['video_desc'])) {
     //save the metadata
     update_post_meta ($post_id, '_video_type', strip_tags($_POST['video_type']));

    update_post_meta ($post_id, '_video_desc', strip_tags($_POST['video_desc']));

    update_post_meta ($post_id, '_video_rating, strip_tags($_POST['video_rating']));

That's it! Save the above code in a PHP file and name it the same name as before and allow it to overwrite the original plugin file if you were following along and it will add another meta-box and a couple more custom fields to your custom post type. Now you should have enough information to be able to make your own custom admin meta-boxes and fields for your next WordPress plugin or theme. Here is an image of the two meta-boxes from when I tested the above code myself:



Now you should know more than enough to make your own plugin or custom theme with its own admin meta-boxes and custom fields for any custom post types you may have. It is important to know that you can also use any other type of form element in the above examples. Feel free to experiment and use textareas, radio buttons, checkboxes etc in your own code.


How to Stop Admin Emails Upon New User Registration in WordPress

It took me quite a bit of messing around to stop admin emails on new user registration to my WordPress site today, so I'm documenting the final solution here. The key is the pluggable function named wp_new_user_notification, but simply replacing the function in your theme's functions.php file does not always(or maybe ever) work, so the final solution I found to work was to replace the pluggable wp_new_user_notification function inside a very simply light-weight plugin. Simply copy and paste the code below into a file and name it Disable_User_Notifications_To_Admin.php. Then upload it to your site's plugins directory and go to wp-admin and activate it. Simple, easy, quick and DONE!


 * @package Disable_User_Notifications_To_Admin
 * @version 1.0
Plugin Name: Disable User Notifications To Admin
Plugin URI:
Description: This is just a simple plugin to stop those annoying admin emails each time a new user registers to your site. simply change the value of in the main plugin file with the email you do not want to recieve notifications at and it will block them.
Version: 1.0
Author URI:
change the value of below with the email you do not want to recieve notifications at and it will block them.
if(!function_exists('wp_new_user_notification')) :

function wp_new_user_notification($user_id, $plaintext_pass = '') {
    $user = get_userdata($user_id);
    $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);

    if ( empty($plaintext_pass) )

    $message  = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
    $message .= sprintf(__('Password: %s'), $plaintext_pass) . "\r\n";
    $message .= wp_login_url() . "\r\n";
if($user->user_email != "")
    wp_mail($user->user_email, sprintf(__('[%s] Your username and password'), $blogname), $message);




That's pretty much guaranteed to work if nothing else has.


Sell PHP, JavaScript, C++, C# and Other Scripts and Tools on

Yes, we have started a store on which can be found at Currently shoppers can find a limited collection of my own scripts and tools for sale. I would like to give my readers a chance to sell their own script and tools here as well, so I am opening it to the public upon approval by me of course. As long as I can see that your scripts are useful and have a potential that someone visiting my site will purchase them, I will publish them. To submit your script for review, simply send me an email at with a link to your script or attach it to the email and include the amount you expect to receive for each sale made and I will promptly give you a decision on whether or not we will sell your items on

Email Ian at to sell your scripts today! Visit our script and tool shop at

Creating a Web Development Environment

This week, I decided it was time to upgrade my web development tools. When you reach my age and have been coding for over 20 years, you have to upgrade every once in a while. I am doing this because I know there are faster and better ways to do what I do everyday. I also wanted to document the new system I create for myself as a seasoned web developer so that those of you just starting out can gain some insight.

Defining your Development Needs

First, I had to layout what my needs as a web developer were. I simply made a list of the technologies I use every day and some I use regularly but not every day necessarily and ordered the list in order of priority. The first items on my list are technologies I use the most:

  1. PHP
  2. HTML
  3. CSS
  4. JavaScript
  5. MySQL
  6. WordPress
  7. Woocommerce
  8.  jQuery
  9. Photoshop
  10. SEO
  11. Three.js 3D programming
  12. FTP
  13. Perl
  14. C++
  15. C#
  16. Ajax
  17. Blender
  18. Gimp
  19. Unity 3D Development
  20. XHTML
  21. XML

As you can see, I use over 20 web technologies in my day to day work and I didn't even list them all, but those are the most significant ones off the top of my head that I use. My goal is to put together a work environment with the most important of those technologies in mind. Ultimately I wish to create an environment that focuses on speed and the ability to make the top technologies I use to work together in a more organized fashion. For example an app that allows me to code in many languages and preview server-side code live in a local server would be one of the primary objectives of my new routine.

With that in mind, I am going to narrow down my above list to what I use in my day to day work from which I actually make money from and do the most. Those would be mostly the ones at the top of my list, but this gives me the opportunity to rethink what I need the most and come up with a work environment that best facilitates my needs as a web developer. Here's what I came up with in the end:


  • PHP
  • HTML
  • CSS
  • JavaScript
  • MySQL
  • WordPress
  • Woocommerce
  • Graphic Design
  • SEO
  • FTP
  • Perl


Several of the items in my first list were related to JavaScript such as jQuery, Three.js and Ajax, so really, my main objective is to just have JavaScript available in my work environment and it will basically cover all the related technologies as well for the most part. There is no way we are going to make an efficient work environment with over 20 technologies, so it is important to narrow your list down as much as is practical. There were also a few different methods of creating graphics on my first list and instead of naming Photoshop, Gimp, Blender, etc, I just put "Graphic Design" on my short-list because that enables me to think in more broad terms about what applications I can use that might be able to accomplish the same tasks as those tools all rolled up in a more advanced tool(if that is possible).

Searching for Applications

My next task was to find programs and applications that will help speed up the web development process. First, I will list the programs and applications I use currently and from there figure out where I can make improvements. So I copy and paste my short-list from above and add after each technology what tool or program I use to accomplish tasks related to each technology:


  • PHP ------------------- Notepad++, Filezilla, Firefox, IE, Safari, Chrome
  • HTML ----------------- Notepad++, Filezilla, Firefox, IE, Safari, Chrome
  • CSS -------------------- Notepad++, Filezilla, Firefox, IE, Safari, Chrome
  • JavaScript ----------- Notepad++ , Filezilla, Firefox, IE, Safari, Chrome
  • MySQL ---------------- Notepad++, PHPMyAdmin, Firefox, Putty
  • WordPress ----------- Notepad++, wp-admin, Filezilla, PHPMyAdmin, Firefox, IE, Safari, Chrome, Putty,
  • Woocommerce ----- Notepad++, wp-admin, Filezilla, PHPMyAdmin, Firefox, IE, Safari, Chrome
  • Graphic Design - Photoshop, Gimp, Blender, Unity, MakeHuman, FileZilla, Firefox, Notepad++
  • SEO -------------------- Notepad++, Firefox, Various Service Providers
  • FTP -------------------- Filezilla, Notepad++
  • Perl -------------------- Notepad++, Putty, Filezilla

So from the above exercise, I was able to make a comprehensive list of the programs and applications I use when doing my web development work:

  1. Notepad++
  2. wp-admin
  3. Filezilla
  4. PHPMyAdmin
  5. Firefox
  6. Internet Explorer(IE)
  7. Safari
  8. Chrome
  9. Putty
  10. Photoshop
  11. Gimp
  12. Blender
  13. Unity
  14. MakeHuman

So out of those 14 programs, I don't actually use them all everyday and I use some more than others. For example, I am more of a programmer than a graphic designer. That's why I call myself a "Web Developer" and not a "Web Designer". So numbers 10 - 14 on the list can go into my "Nice to Have" category and do not require crucial changes since I only use them every once in a while and it's not a huge deal to keep using what I use now for those. If you are primarily a web designer however, these applications would be higher up on your list of tools you use and you WOULD want to give more thought to whether you can find better tools and tools that can combine the abilities of several of those. For example, Photoshop can do everything Gimp can do for the most part, so you might want to drop Gimp as a regular tool and use Photoshop more often. Then Unity, Blender and MakeHuman are all 3D modeling tools used more for video game development than web development, but if you use these regularly, you can probably search and find a tool that does most of what you need to do using those tools all rolled up in one good tool. Actually Unity is close. I try to learn to do what models and textures I can right in Unity instead of going to Blender to create them and then import them into Unity which takes more time, but sometimes it is still necessary to do.

Anyway, being first and foremost a web developer and not a designer, the tools most important to me right now are the first ones on my list and can be narrowed down to these:

  1. Notepad++ is what I currently use for most of my coding needs.
  2. PHPMyAdmin is a must have for all of my MySQL database manipulation needs currently.
  3. Filezilla is what I always use to download files from client's web servers. Then I edit them and upload them back to the server using Filezilla once again.
  4. Firefox is my web browser of choice since it is by far the most standards compliant of all the available popular web browsers. The others listed above are only used at the end of a project to check for cross-browser compatibility and there is no real way to get around having to use them all to properly debug your web applications.
  5. Putty is a great tool I also use often to access client's web servers for just about anything that I cannot do through the Filezilla FTP program. Tasks I use Putty for include tweaking PHP settings, changing ownership of files and editing server configuration files.

The next thing I have to ask myself is where can I make improvements in my development process and what tools are involved. After that I can search for better tools to accomplish those goals. From what I gather after examining my own habits and tools that I use, I figure the most improvement can be made in the areas of FTP, Code editing and Previewing the results of the code I write.

I came up with the above conclusion by thinking about where it seems like I waste the most time. Also I kept in mind what is possible to change and I figured that recent developments in developer tools probably will allow me to be able to improve the way I edit code, the way I update files and the way I view server-side scripts while in the process of coding them. Here's my current most common process in my day to day work routine:

  1. I go to Firefox and locate the problem on a client's website or the area of the website that they may want something added to.
  2. Then, I open Filezilla and locate the files involved that need editing on the server and download them to my desktop for editing.
  3. Next, I will normally open Notepad++ and work on the PHP, HTML, CSS and/or JavaScript code until a portion of the solution is accomplished.
  4.  Then I have to use Filezilla again to upload that file back to the web server for testing.
  5. After that, I open the webpage in Firefox to see if it works and to plan what I have to do next.
  6. I go back to Notepad++ and make more changes.
  7. I upload with Filezilla again and again view the progress in Firefox and keep repeating steps 4,5 and 6 until the changes appear correct.
  8. Then finally, I check the progress in all other popular browsers such as IE, Chrome and Safari to make sure it all works. Again here I have to repeat steps four through six some more until all problems are resolved with cross-browser compatibility.

As you can see, there are some seriously repeated functions that can take up a lot of precious development time in my current process. The best way to speed the process up would be to eliminate the process of having to upload the files to he server every time I make a round of changes and view it in a browser then go back to notepad++. With this acknowledgement in mind, I need to find a tool that allows me to do the following important steps in my web development process:

  1. edit several types of code in one place.
  2. get the code to the server seamlessly for testing.
  3. and view the output in a browser.

So the best place for improvement in my process is within those three steps. If I could find the perfect tool to accomplish all three, that would be perfect.

Finding Tools to Improve your Workflow

So, while looking for tools to accomplish these feats, Here is what I found.


The first one I tried after reading reviews and program descriptions all across the web, was a not-so-well-known application called CyberDuck. After testing CyberDuck for about a week or so, I found that it met most of these needs, but had it's pros and cons like any other application. Let's examine those pros and cons:

CyberDuck Pros:

  • allows for the importing of FTP connection information from Filezille to CyberDuck. This is great because if you have a lot of clients like I do, you have a lot of FTP connections and it would take a lot of time to copy them all manually. In CyberDuck, they call FTP connections "bookmarks" this was strange to me and I didn't know what they were for the first day or so, but once I figured out what they were, I was able to use the application much more efficiently.
  • CyberDuck has an FTP application built in.
  • It allows you to link your favorite text editor or code editor to the FTP function so all you do is click on a file in the server's document tree and it opens in an editor on your local machine! So, it downloads a copy of the file and opens it in your editor in other words. So in my case, I click on a file in the document tree and it opens up in Notepad++ for editing.
  • When I save the file after making changes in Notepad++, it automatically uploads the changes to the remote server without me having to do anything but click on "Save" in Notepad++. This saves a lot of time. Even though I am actually using two programs, CyberDuck and Notepad++, it seems like I'm only using one because there is a nice seamless integration of the two performed within CyberDuck.

Cons of Using CyberDuck

There are not a lot of cons, but the ones that bothered me were:

  1. It drops the connection to the server more often than Filezilla did it seems like.
  2. While it combined two of my three main functnionalities I was seeking, it did not allow for viewing of the code changes live on the server. I still would have to go to Firefox to do that.

All in all, CyberDuck is a great tool. It is still new and has some bugs to work out, but I will definitely follow it and use it while looking for a better solution. Perhaps it will evolve into that perfect solution in a future version. Who knows.

CodeLobster PHP Edition

Next I got an email to let me know of a new program called CodeLobster that was supposed to be the perfect PHP code editor and much more. I am giving it a try right now, so I'll have to come back with most of my review of CodeLobster, but right out of the box I notice that it has a wide range of code editing abilities and features, is expandable and very well made. The only drawbacks I've noticed so far are minor such as the word wrap feature breaks up words in bad places and there is no spell check that I can find for editing plain .txt files. It seems great for editing PHP code so far though.


Want to learn more about SEO? Check out these relative books from Amazon:

How to Edit Woocommerce Shop Pages

In order to edit your Woocommerce shop pages such as the main shop link and other pages within Woocommerce , the best way to get started is to go to the woocommerce directory at plugins/oocommerce and copy the woocommerce/templates folder into your current theme directory. Then rename the templates directory you copied into your themes main directory to woocommerce. Now you have all the templates for Woocommerce pages being overridden by the templates in the woocommerce folder inside your current theme! Now you can edit the pages without having to worry about messing up the original Woocommerce files.

Create a Dropdown of Product Categories in Woocommerce

A recent project demanded that I create a drop-down list of Woocommerce product categories for an admin page in a plugin I was creating. Here is the PHP and HTML code that accomplished the task:

<form method="post" action="">
<?php $args1 = array('taxonomy'  => 'product_cat'); ?>
  <?php wp_dropdown_categories( $args1 ); ?>
<input type="submit" name="cat_sel" value="SELECT PRODUCT CATEGORY" />
</form><hr />

Retrieve Selected Category in Form Processing Script

Now to retrieve the value, you will use the post variable named cat like so:

$chosen_cat = $_POST['cat'];

...and that will return a product ID. If you need a product name, here is cool PHP function I found that returns the post name/slug when feeding the function the ID we just stored in $chosen_cat above:

function get_product_category_by_id( $category_id ) {
    $term = get_term_by( 'id', $category_id, 'product_cat', 'ARRAY_A' );
    return $term['name'];
$product_category = get_product_category_by_id( $your_category_id );


How to Remove Fields from Woocommerce Edit Address Form

To remove the country field from the checkout and "edit my address" pages, you have to remember to remove it not only from the billing address but the shipping address as well. Here is the example code to accomplish this. Paste the below code into functions.php of your current theme and it should work perfect.

add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
add_filter( 'woocommerce_billing_fields' , 'custom_override_billing_fields' );
add_filter( 'woocommerce_shipping_fields' , 'custom_override_shipping_fields' );

function custom_override_checkout_fields( $fields ) {
  return $fields;

function custom_override_billing_fields( $fields ) {
  return $fields;

function custom_override_shipping_fields( $fields ) {
  return $fields;

Now you can alter the above code to fit your needs. Some of the field names you may want to remove include:

How to add Keyword Meta Tags to Woocommerce Product Categories

Today I spent hours trying to figure out the best way to add keyword meta tags to product category pages in Woocommerce without adding yet another plugin to slow my site down. Here is the final solution I ended up doing to add meta keyword tags to product category page in WordPress.

Product categories use a special WooCommerce page template located in wp-content/plugins/woocommerce/templates/ in a file named archive-product.php. If you open that file you'll notice the get_header WordPress function looks like:


Okay so if you understand the WordPress get_header function you'll know this indicates that there is a special header file involved here.  The get_header function appends what's in the parenthesis to the prefix: "header-" then appends ".php" to the end in order to create the file name of the header file for the template it's called within. That means in this case it points to a file named "header-shop.php". Therfore the first thing you need to do is check your active theme directory for a file named header-shop.php. Most themes do not have this file and by default, it calls the header.php file if header-shop.php does not exist.

Edit or Add header-shop.php File:

If you found the header-shop.php file, great, simply edit it to your needs and done. In my case if I had found one, which I didn't, all I would have had to do would be to add meta tags under the title tag in the head section of the file.

If you did not find header-shop.php, then make a copy of header.php and name it header-shop.php and upload it to the same directory as header.php. Then you can edit header-shop.php to only make changes to pages that use that header tempalte such as the product category pages. In my case, I wanted to add custom meta tags to the product category pages, so I added the following inside of the head tags in header-shop.php and uploaded it to the current theme folder:

<meta name="description" content="insert your custom product category description here." />
<meta name="keywords" content="your keywords go here, separate with commas" />


How to make a WooCommerce Product Importer

Okay, I've had to do this for two clients this month, so I thought I'd write a post on how to make a product scraper that works with WooCommerce and WordPress.

2 Ways to Make a Product Importer


Before you begin, both method described in this article use the simple HTML Dom library for php which you can download HERE, just download the file and change it from a .txt file to a .php file and include it at the top of your scripts as you'll see below. You may have to copy and paste it into a blank PHP file from the browser window.

The two most common ways to import products from an external source is probably either to scrape the site you want to sell products from or get an Excel or CSV file directly from your product supplier. I have done both methods so will cover the basics here. If you need this done and don't want to do it yourself as it is rather complex, hire me and I'll do it for you at a very reasonable price since I have experience doing it now.

Using an Excel file from the Product Vendor

If you get an excel file from a vendor, you'll need to write an algorithm or application in PHP to convert the Excel file into a CSV file compatible with the CSV importer plugin for WooCommerce seen below:


So you prob have an Excel file from your supplier that looks something like this:


Now to work with the CSV Importer plugin for WooCommerce and WordPress, you need it in CSV format specially formatted to provide specific product information for your shopping cart. The CSV file needs to look something like this one I made for a client recently;

2156635698;2156635698;3.25 carat round brilliant loose certified diamond;Color: F,Cut: EX,Clarity: SI2,Shape: round brilliant,Loose GIA certified diamond with certification number 2156635698;Color: F,Cut: EX,Clarity: SI2,Shape: round brilliant,Loose GIA certified diamond with certification number 2156635698;loose certified diamonds;GIA certified|colorless|Slightly Included|Peter Michaelson Jewellery;1;61261;
2131664334;2131664334;2.35 carat round brilliant loose certified diamond;Color: E,Cut: EX,Clarity: VS1,Shape: round brilliant,Loose GIA certified diamond with certification number 2131664334;Color: E,Cut: EX,Clarity: VS1,Shape: round brilliant,Loose GIA certified diamond with certification number 2131664334;loose certified diamonds;GIA certified|colorless|Very Slightly Included|Peter Michaelson Jewellery;1;63694;

Above is what the .csv file looks like opened in a text editor, open it in Excel and it looks a little nicer as you can see below:


So the goal here is to convert the below Excel on the left to the CSV file on the right to use with CSV Importer:



Here is how to convert the Excel file to a CSV file you can upload as a product list into your WordPress WooCommerce website:

Instead of providing a very long explanation about how to make this Excel xlsx to csv file converter, I'm just going to get you started with some code that you can modify to fit your unique situation:

<!DOCTYPE html>
<title>CSV Maker</title>
<table id="results-table" border="1" cellpadding="3" style="border-collapse: collapse">
<th style="font-size:10px">Fluorescence</th>
<th>Cert. No.</th>
//search code:
require_once "simplexlsx.class.php";
$xlsx = new SimpleXLSX('products.xlsx');

//start variable to hold CSV output for woocommerce importer:
$CSV = 'sku;post_name;post_title;post_content;post_excerpt;category;tags;stock;price;featured_image'.PHP_EOL;

list($cols,) = $xlsx->dimension();
foreach( $xlsx->rows() as $k => $r) {
if ($k == 0) continue; // skip first row
//start variable to show cur row:
$curRow = '';
$curRow .='<tr>';
for( $i = 0; $i < $cols; $i++) {
//if i=0 it is carat:
$car = $r[$i];
$curRow .='<td>'.$car.'</td>';

//if i=1 it is shape:
$shp = $r[$i];
$shp = strtolower($shp);
$curRow .='<td>'.$shp.'</td>';

//if i=2 it is dimensions:
$dim = $r[$i];
$curRow .='<td>'.$dim.'</td>';

//if i=3 it is color:
$col = $r[$i];
$curRow .='<td>'.$col.'</td>';

//if i=4 it is clarity:
$cla = $r[$i];
$curRow .='<td>'.$cla.'</td>';

//if i=5 it is cut
$cut = $r[$i];
$curRow .='<td>'.$cut.'</td>';

//if i=6 it is certificate type ie: GIA
$cer = $r[$i];
$curRow .='<td>'.$cer.'</td>';

//if i=7 it is fluorescence:
$flo = $r[$i];
$curRow .='<td>'.$flo.'</td>';

//if i=9 it is Price:
$pri = $r[$i];
$curRow .='<td>$'.$pri.'</td>';
}//end for loop for ea. column.
$curRow .='</tr>';
//show row:
echo $curRow;
//build csv file content:
//carat = $car
//shape = $shp
//dimensions = $dim
//color = $col
//clarity = $cla
//cut = $cut
//cert type = $cer
//fluoresence = $flo
//price = $pri

/* make following CSV fields from above data:
//test print ea. column of the excel sheet:
echo "<tr><td>carat=$car</td><td>shape=$shp</td><td>measure=$dim</td><td>color=$col</td><td>clarity=$cla</td><td>cut=$cut</td><td>c type=$cer</td><td>fluorescence=$flo</td><td>price=$pri</td></tr>";
//build product description

//build sku using cert no.:
$sku = $certno;
//make post name cert no too:
$post_name = $certno;
//make the post title be the carat and the shape:
$post_title = $car." carat ".$shp." loose certified diamond";
//make post content be color, cut, clarity, shape, certificate type and no.
$post_content = "Color: $col,";
$post_content .= "Cut: $cut,";
$post_content .= "Clarity: $cla,";
$post_content .= "Shape: $shp,";
$post_content .= "Loose $cer certified diamond with certification number $certno";
//make post excerpt the same as post content:
$post_excerpt = $post_content;
//make category be loose certified diamonds:
$category = 'loose certified diamonds';

//make tags be cert, type, color, clarity Peter Michaelson Jewellery.
//if color is d, e, f, it is colorless if it is g, h, i, it is near colorless
if($col == 'D'||$col == 'E' ||$col == 'F' ){$coltag = 'colorless';}else{$coltag = 'near colorless';}
//clarity>>> IF=Internally Flawless | VVS1/VVS2=Very, Very Slightly Included | VS1/VS2=Very Slightly Included | SI1/SI2=Slightly Included | P1=Included
if($cla=='IF'){$claritytag = 'Internally Flawless';}
if($cla=='VVS1/VVS2'){$claritytag = 'Very, Very Slightly Included';}
if($cla=='VS1/VS2'){$claritytag = 'Very Slightly Included';}
if($cla=='SI1/SI2'){$claritytag = 'Slightly Included';}
if($cla=='P1'){$claritytag = 'Included';}
$tags = $cer." certified|";
$tags .= $coltag."|";
$tags .= $claritytag."|";
$tags .= "Peter Michaelson Jewellery";
//End making tags for csv.

//build stock for csv:
$stock = 1;
//build price for csv:
$preprice = $pri * 0.15;
$price = $pri + $preprice;
//build featured_image for csv:
if($shp=='round brilliant'){
$fimg = '';
$fimg = '';
$fimg = '';
//build csv file contents using above variables such as:
//sku post_name post_title post_content post_excerpt category tags stock and price
$CSV.= $sku.";";
$CSV.= $post_name.";";
$CSV.= $post_title.";";
$CSV.= $post_content.";";
$CSV.= $post_excerpt.";";
$CSV.= $category.";";
$CSV.= $tags.";";
$CSV.= $stock.";";
$CSV.= $price.";";
$CSV.= $fimg.PHP_EOL;

}//end foreach loop for each row.
//test and debug show csv file content:
echo "<hr />CSV contents:<br />$CSV<hr />";

//write to csv file after foreach loop:
$myFile = "products.csv";
$fh = fopen($myFile, 'w') or die("can't open products.csv file");
fwrite($fh, $CSV);
//provide a download link to the CSV file:
echo "<p><a href='$myFile' target='_blank'>Download .CSV/Excel File!</a></p>";


Okay, there you have it! Now on to the next way of getting products into WooCommerce.

Scraping Products from another Website

If you can't get the provider to provide an Excel sheet or product list of some sort, you may have to resort to scraping thier website. Here is a script I wrote to do just that:

First, the HTML:

<h2>Product Scraper for</h2>
Created By: Ian L. of <a href=""></a>

<hr />

<form action="apmex-scraper5.php" method="post">
<td>Page no.:<select id="pgn" name="pgn"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option></select></td>

<input id="kwrd" type="text" name="kwrd" value="gold" /></td>
<td>Per/Pg:<select id="per" name="per"><option>60</option><option>5</option><option>10</option><option>20</option><option>30</option><option>40</option><option>50</option></select></td>
<td><input id="sbt" type="submit" name="sbt" value="Scrape Now" /></td>

Then the PHP main page:

//Exports products in given category from into csv file for importing into woocommerce.
$pgno = $_POST['pgn'];//the page no. for get var in the URL to scrape
$keywrd = $_POST['kwrd'];//keyword to scrape search results of scraped site.
$howmany = $_POST['per'];//how many to scrape per page.

//URL String for searching target site:
$u = "";

include 'simple_html_dom.php';

$html = file_get_html($u);//string of HTML for gallery pg
//echo "HTML:".$html;

include 'functions19.php';

//get the short descriptions:
$s = '
<div class="products-item-description">';//'
$e = ' get_short_desc($s,$e,$html);</div>
//get the links to product page:
$s = '<h3 class="products-item-title"><a href="';<br />
$e = '">';
//get the price and mark up 15%:
$s = '<h3 class="heading-blue">Volume Pricing</h3>';//'1 - ';
$e = '<div class="products-item clearfix">';//'</div>';

//now short-desc, link & price all are in arrays, $d, $l and $p

$icnt = count($l);
echo "Processing $icnt items";
//start the csv file contents variable:
$csv = "post_name,featured_image,post_excerpt,sku,stock,post_title,price,category,post_content,product_gallery,product_id".PHP_EOL;

$ii = $i+1;

$de = $d[$i];//short desc
$pr = $p[$i];//price
$li = $l[$i];//link
echo "
<h2>Link text we get title from is:</h2>
//get the title from the link
$tia = explode("/",$li);//title array will have title at key 5
$ti = $tia[5];
//replace - with space in title:
$ti = str_replace('-',' ',$ti);
//capitalize title:
$ti = strtoupper($ti);
echo "Title: $ti

//build cats var for csv file:
//now get the html for breadcrumb/categories:
$html3arr = explode('

<nav class="breadcrumbs">',$html);//key 1 wil have breadcrumbs/cats
$bcchunk = $html3arr[1];//has cats plus, so cut off at</nav>$bccarr = explode('

',$bcchunk);//key 0 is html3 we need for cats!
$html3 = $bccarr[0];//echo "HTML for cats:
$catarr = explode('<a href=""/category/',$html3);//key"> //count cat array:
$ccount = count($catarr);
$countmin = $ccount-1;
$cats="";//variable to hold categories(resets it too)
$capkey = ucwords($keywrd);//captialize first letter of ea. word in keyword
$cats .= $capkey;//adds keyword as first category.</a>

$catcode = $catarr[$k];//has txt b4 and after cat.
$catcodearr = explode('">',$catcode);//key 1 will have cat followed by extra txt
$catplus = $catcodearr[1];//has cat plus txt after.
$catplusarr = explode('',$catplus);//key 0 is just cat!
$cat = $catplusarr[0];//echo "

cat found: $cat

$cat = trim($cat);//trim cat
//see if cat is equal to keyword in all its captialized forms
if($cat == $capkey) {
//if it matches don't add it, so do nothing!
}else{//else its not the keyword that was added first, so add it:
//add a pipe at start since its not first one
$cats .= '|';
$cats .= $cat;
}//end if/else cat is same as keyword in a case insensitive comparison
}//end for loop going over cats.

//get the product description for main content:
$darr = explode('
<h2>Product Description</h2>
',$html2);//key 1 will have description plus some
$desplus = $darr[1];//desc plus txt b4 and after
//if it uses a table, get til

if it uses a ul list get til


$desarr = explode('

',$desplus);//key 0 is desc with some before
$desarr = explode('',$desplus);//key 0 is desc with some before
}//end if/else desc uses table.
$desandb4 = $desarr[0];//desc may have
and before that needs taken off
$descr = explode('
',$desandb4);//key 1 will b just desc!
$desc = $descr[1];
}//end if/else desc has part we don't want at start

//strip HTML tags from desc:
$desc = strip_tags($desc);
//now replace @@@ with br tags:
$desc = str_replace('@@@','

//clear desc of any commas that will confuse csv file:
$desc = str_replace(',','',$desc);

//put the data into a CSV file for importing into woocommerce:
$csv .= $ti.",";//add title for post name to csv file
$csv .= $im.",";//add gallery image url to csv file
$csv .= $de.",";//add long desc to csv file
$csv .= $sk.",";//add sku to csv file
$csv .= "99,";//add stock to csv file
$csv .= $ti.",";//add title for product title to csv file
$csv .= $pr.",";//add price to csv file
$csv .= $cats.",";//add categories to csv file
//add desc/post_content to csv file:
$csv .= $desc.",";//add desc.
//add product pics to csv file last before eol because no comma after them!
$curdir = $_SERVER['SERVER_NAME']."/".basename(__DIR__);//dirname(__FILE__);//getcwd();//gets the directory name this script is run from.
for($j=0;$j<5;$j++){//changed j=1 to j=0 for dgrundel scraper because it includes feature img here
$cpic = $pics[$j];
//if there is another img after this one, add a pipe separator:
$cpic .= "|";
$csv .= $cpic;
//do nothing...
}//end if less then j pics...else...
}//end for loop adding pics to csv file.
$csv .= ",".$pidno;//add product ID to csv file.
$csv .= PHP_EOL;//eol to csv file last
}//end for loop
//write CSV file:
$myFile = "$keywrd-products-r$pgno.csv";
$fh = fopen($myFile, 'w') or die("can't open silver-products.csv file");
fwrite($fh, $csv);
//provide a link to the file to download it:
echo "

Done Creating CSV file!

<a href="$myFile" target="_blank">Download $myFile CSV File!</a>


echo "done!";

Finally the helper_functions.php file:

//written for apmex-scraper5.php

//function to retrieve HTML objects by Ian L. of
function get_stuff($start,$end,$htm){
$extras=false;//make true to see extra debugging data specific to their function.
global $dbugHTML;
global $t;//title
global $d;//desc
global $l;//link
global $pics;//product image urls
//global $filez;//product image file names
// split at start to get chunk we want:
$html_array = explode($start,$htm);
$o_a = explode($end,$objct);//key 0 should be part we need.
$o = $o_a[0];
if($dbugHTML){if($extras){echo "Object $i: $o
//put in title($t) or desc($d) array according to $end var:
//if $end is '' its a desc and if $end=its a title:

//put the link to next pg in l array:
if($end == '">'){$l[]=''.$o;}//fill link array

//put the product images in the pics array:

when running run no. 18, it had 26 pics with functions.php.
when running with functions18.php it had 45 pics. using curl to check imgs.
#the above is not relevent with new dgrundel csv scraper because it will not get images that have ashx in the url so I fixed it by changing the thumb name instead. Made the thumb change in woo-product-importer-ajax.php(dgrunden csv importer plugin file)
if($end == '" title="' && $start == '

//get img try one:
//take out: handlers/ThumbJpeg.ashx?VFilePath=~/
$otry1= str_replace("","",$o);
$otry1= str_replace(" ","%20",$otry1);
$oar = explode("&",$otry1);//now key 0 is just the img url!
$otry1 = $oar[0];

//test to see if image works:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$otry1);
// don't download content
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

echo "<h2>GOT IMG!</h2>";

$pics[]=$otry1;//fill pics urls array
//The img is good, so do nothing...
}else{//else if image doesn't work, try different method of getting img:

echo "<h2>TRY TWO TO GET IMG!</h2>";

echo "Failed try one: $otry1";

//take out: handlers/ThumbJpeg.ashx?VFilePath=~/
//$otry2= str_replace("","",$o);
$otry2 = str_replace(" ","%20",$o);
$oar = explode("&",$otry2);//now key 0 is just the img url!
$otry2 = $oar[0];
$pics[]=$otry2;//fill pics urls array
if($extras){echo "Try two img: $otry2";}
}//end else img didn't work so tried another way.

//took this out because we don't use the filez array it seemed and $oo doesn't exist!:
//$ooo = str_replace('','',$oo);
//$filez[]=$ooo;//file pic file names array
}//end if img...

if($dbugHTML){echo "<hr />";}
}//end get_stuff function.

//function to retrieve price and mark up 15% - by Ian L. of
function get_prices($start,$end,$htm){
global $dbugHTML;
global $p;
$extras=false;//set to true to see extra debuggind info specific to this function.
// split at start to get chunk we want:
$html_array = explode($start,$htm);
//$del = array($start, 'Any Quantity');
// explode by array of delimiters In one swoop:
//$html_array = explode( $del[0], str_replace($del, $del[0], $htm) );

$hcntactual = $hcnt-1;
if($exras){echo "
<h2>Prices code blocks found: $hcntactual(not all may have actual price in them)</h2>
if($hcntactual < $howmany){echo "
<h3 style="color: red;">ERROR! only $hcntactual of $howmany price blocks found...</h3>
$o_a = explode($end,$objct);//key 0 should be part we need.
$o = $o_a[0];
//take out price:
$o_a2 = explode('$',$o);//key 2 should have orig price plus extra txt
$o2 = $o_a2[2];//price with extra text and commas that need removed
//remove all aft:
$o2a = explode(' ',$o2);//key 0 is just price w/commas
$o2 = $o2a[0];//price w/commas
//remove commas from price text and make a number:
$o3 = str_replace(",","",$o2);
if($dbugHTML){echo "$i - Orig. price:$o3";}
$price = $o3 * 0.15;
$price = $price + $o3;
$price = round($price,2);
echo "Mark-up price:";
printf("%.2f", $price);
echo "";}
}//end while.
if($dbugHTML){echo "<hr />";}
}//end get_prices function.

//function to retrieve woocommerce short desc by Ian L. of
function get_short_desc($start,$end,$htm){
global $dbugHTML;
global $d;//short desc

// split at start to get chunk we want:
$html_array = explode($start,$htm);
$o_a = explode($end,$objct);//key 0 should be part we need.
$o = $o_a[0];
//put the short description in the d array:
//take commas out to not confuse the csv values:
$o = str_replace(",","",$o);
//see if has ' ' and take out it and before if so:
$findstr = ' ';
if(strpos($o,$findstr) !== false){
$farr = explode($findstr,$o);//key 1 will be all after findstr.
$o = $farr[1];
}//end if had ''
//trim short desc:
$o = trim($o);
//replace any instances of apmex with Goldecom
$o = str_replace('apmex','Goldecom',$o);
$o = str_replace('Apmex','Goldecom',$o);
$o = str_replace('APMEX','Goldecom',$o);
if($dbugHTML){echo "Short Desc $i: $o";}
$d[]=$o;//fill description array:
}//end while going over html_array
if($dbugHTML){echo "<hr />";}
}//end get_short_desc function.

Important Note:

If you copy and paste code from almost any WordPress blog, including this one, WordPress normally changes single and double quotes(" and ') to fancy ones. You can easily do a find & replace in any text editor to change them back, but if you do not, the script will not function as expected or may not work at all.