Eric Platt, Developer
(619) 733-9186

San Diego, CA

Slide background
Slide background
Slide background

All photos on this site are by Eric Platt and are © Copyright 2001-2013 Eric Platt

USABILITY & USER INTERFACE DESIGN & CONSULTING

UX/UI: USER EXPERIENCE & USER INTERFACE DESIGN

WEB  DEVELOPMENT SERVICES

WORDPRESS & SQUARESPACE / MOBILE APPS

COPYWRITING, RESEARCH

CREATIVE PROBLEM SOLVING & ENGINEERING

Author Archives: Eric Platt

Building a Plugin

In this article I am going to record my adventure of developing a simple WordPress plugin. I want to do something as simple as possible, yet interesting enough to make it worthwhile. And hopefully fun.

Step 1. What’s it going to do? The basic idea is to show some statistics of the WP site, such as number of pages, posts, plugins, WP version, etc., and place this in an easily accessible area. Will start with just putting it in the Admin area (Like Hello Dolly plugin).

2. Give the plugin and file a name: research if a similar plugin and name already exists. “People who install your Plugin will be putting this PHP file into the WordPress Plugin directory in their installation, wp-content/plugins/, so no two Plugins they are using can have the same PHP file name.”

Was thinking of “stats” or “reporter”. But there are “stats” plugins that have to do with showing statistics of the number of visitors. “Report” or “Reporter” looks like a better candidate.

Search to make sure name isn’t taken: http://wordpress.org/extend/plugins/

Am going to try “report.php” – I assume one can always change it later.

Fill in the standard plugin information at the top of your Plugin’s main PHP:

/*
Plugin Name: iReport
Plugin URI: http://devtegrity.com/ireport
Description: Shows some interesting internal information about your WP site.
Version: 0.1
Author: Eric Platt
Author URI: http://devtegrity.com
License: GPL2
*/

Upload via FTP, and refresh the page, and voila! It appears in the list of plugins. It doesn’t do anything yet, so there’s no point in activating it at this point.

OK we want it to report the number of posts, so what kind of WP function is there for that?

wp_count_posts( $type, $perm ) might do it.

OK got the plugin to write “TEST” in the upper right hand corner.

In playing around, got a PHP error (there was a syntax error in the echo statement), then a “fatal error” could not activate plugin before the page was refreshed. Then when I tried to move “wp_count_posts();” into “$report = getNumPosts();” to yield

$report = wp_count_posts(); , got just a blank page for the plugins.

It’s still not showing the number of posts.

Testing out the PHP syntax – this function needed a “return” to send ti’s information:

function getNumPosts() {
/* Get the number of posts */
$numPosts =   2;
return $numPosts;
}

As soon as I try and use “wp_count_posts()” (putting it in instead of 2) I get a blank screen.

A little research on using getNumPosts() reveals that one needs to use ->publish:

function getNumPosts() {
/* Get the number of posts */
$ep_wr_numPosts = wp_count_posts()->publish;  
return $numPosts;
}

Woohoo! it works.

What next? How about adding another line of information, such as the WordPress version, before we go on to UI or settings enhancements. We’ll also want this new info to appear on another line.

Looks like “get_bloginfo( $show, $filter )” is the function we want. It has a number of possible parameters for $show.

http://codex.wordpress.org/Function_Reference/get_bloginfo

get_bloginfo(‘version’);

Great, OK, that worked. Had to put both variables for the output into one echo line, since otherwise it goes and generates each separately, applying the CSS float each time.

Alright, what else do we want to show. I’d like to add at least one fore item before going on to styling and UI, settings.

Number of pages. All you have to do is add a parameter to wp_count_posts: wp_count_posts(‘page’);

Added a function. Got a blank page. Deactivated, reactivated. An error, but at least it told me what line. Turns out there was a semicolon in the middle of a line.

Would still like to add another line of data, to see what happens with the layout – if it pushes down the top of the admin layout or overlays it. How about the number of categories? There is no WP function that I can find that returns that, but there is one that returns the names of categories (well, actually “Returns an array of category objects”).

There’s an example on the WP Codex page of using it that has a loop:

$categories=  get_categories('child_of=10');
  foreach ($categories as $category) {
  $option = '<option value="/category/archives/'.$category->category_nicename.'">';
  $option .= $category->cat_name;
  $option .= ' ('.$category->category_count.')';
  $option .= '</option>';
  echo $option;
}

So all we have to do is substitute a counter for all that code and we get the number of categories.

function getNumCategories() { 
  $categories = get_categories(); 
    foreach ($categories as $category) {
  	$counter += 1;
  }
  return $counter;
  }

Works! And there is an overlap:

Well, the data the plugin is displaying so far are all bits of info that are pretty easy to find. A colleague had an idea: what about showing the post ID – this could be useful for example when working on the CSS.

1/1/13

Today I’m going to continue by looking into how to create a settings page – what they call an administration menu. A good place to start is again, the WordPress Codex:

http://codex.wordpress.org/Adding_Administration_Menus

But first, I notice the text at bottom, on the 4th line, is being hidden by a div. So I also want to look into an expanding text area for the “readout”.

Looks like JQuery is the way to do it.

Google search “animated expand collapse toggle click box”

http://stackoverflow.com/questions/6675491/animate-a-div-and-expand-from-center
http://mistonline.in/wp/expand-and-collapse-toggle-div-using-jquery/
http://www.devcurry.com/2010/07/expand-textbox-on-focus-using-jquery.html

None of these did exactly what I want, even after hacking. They separate the button from the text area, or expand and then collapse. Or the text flows outside the box when it’s small.

But this might get me closer:

http://roshanbh.com.np/2008/03/expandable-collapsible-toggle-pane-jquery.html

(Aside: What about calling it “Scope” or “Periscope”?)

Am experimenting with pasting a call to JS into the plugin code, and jQuery, then CSS, working up to making it do th thing I want. Not sure how to handle the HTML. Discovered that you have to take out double quotes in the PHP echo statement.

<script type="text/javascript">
$(document).ready(function(){
//hide the all of the element with class msg_body
	$(".msg_body").hide();
	//toggle the componenet with class msg_body
	$(".msg_head").click(function(){
		$(this).next(".msg_body").slideToggle(250);
	});
});
</script>

OK that works. I’ve got a little expanding list now:

Only problem is … Cannot switch into HTML editing mode when editing a post anymore. Taking out this line fixes it, but we need jQuery:

<script type='text/javascript' src='http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js'></script>

Will try the jquery.com source instead of Google’s:

<pre><script src="http://code.jquery.com/jquery-latest.js"></script></pre>

Ah success!   But what’s the proper way? To use: wp_enqueue_script(‘jquery’);   Put that in one of the functions (I put it in function report_css() ) It still didn’t work. However, the documentation for wp_enqueue_script notes: “The jQuery library included with WordPress loads in “no conflict” mode. This is to prevent compatibility problems with other javascript libraries that WordPress can load… In “no-conflict” mode, the $ shortcut is not available and the longer jQuery is used.” So you either have to use the long form and say “jQuery” instead of “$”, or wrap your JQuery with:

jQuery(document).ready(function($) {
// $() will work as an alias for jQuery() inside of this function
});

I did the latter, and it worked! Read all about wp_enqueue_script here:

http://codex.wordpress.org/Function_Reference/wp_enqueue_script

Going to see if I can get some more useful information into the readout: the post or page ID:

$url = explode(‘?’, ‘http://’.$_SERVER[“HTTP_HOST”] . $_SERVER[“REQUEST_URI”]);

$ID = url_to_postid($url[0]);

(from: http://wordpress.org/support/topic/get-pagepost-id-in-functionsphp-file)

Didn’t work: just gave Post ID: 0

But I have another problem: the dropdown infobar is going under other things:

The solution, I assume, is to use the z-index parameter of CSS. The question is how high a z-number to use, where to put the code. I’m trying z-index: 25 in several different places. Doesn’t seem to have any effect. Further reading on the net (such as here: http://stackoverflow.com/questions/572865/how-to-put-an-element-on-the-top-layer-in-the-middle-of-the-browsers-window) seems to suggest that I only need a z-index of 1. My nephew Ryan suggests position: relative or absolute (is required). I put it into :

.msg_body {
   position: relative;
   z-index: 1;
   padding: 5px 10px 15px;
   background-color:#F4F4F8;
   font-size: 11px;
}

Back to the problem of how to get a post ID outside of “the loop”.

http://wordpress.org/support/topic/getting-current-post-id-out-of-the-loop

Was wondering what the “=>” operator was in PHP. meant. Found some illumination on this page:
http://www.robert-gonzalez.com/2009/03/04/php-operators-double-and-single-arrow
It’s call an “array value assignment operator”.

$post = $wp_query->post;  // Set a property in the $wp_query object called post and put it into $post
                                           // Then pass the function:
$post->ID                        //  Set a property in the $post object called ID

function getPostID() {
$post = $wp_query->post; // Set a property in the $wp_query object called post and put it into $post
$getID = $post->ID;         //  Set a property in the $post object called ID
return $getID;
}

Doesn’t work. Don’t quite understand the OO syntax of PHP perhaps.

http://wordpress.org/support/topic/current-page-id-outside-the-loop

$wp_query->post->ID

That created a blank page

According to this page:
http://www.thewordpressblog.com/basics/get-post-id-inside-and-outside-the-loop/
This should work:

global $wp_query;
$postid = $wp_query->post->ID;

But it doesn’t. So maybe I’m trying to get the ID in the wrong place.

http://www.gravitationalfx.com/using-the-wordpress-post-id-outside-of-the-loop/

This post suggests:

global $post;
$post_id = $post->ID;

Works!

Now the question is, will it worth it pretty permalinks? So I tried changing “Permalink Settings” to “Post name” so that for this page for example, instead of the URL looking like:

http://www.devtegrity.com/wp-admin/post.php?post=1&action=edit&message=1
will look like:
http://www.devtegrity.com/hello-world/
But wait, when you are in edit mode, apparently you can just get the ID from the URL. My plugin works in the Admin pages only, which is what you see when you are in edit mode.

Tried creating a static home page (Through Reading settings) with comments off (in Edit mode, access Screen Options at top to get at check boxes for those settings). But it’s the same: shows ID in URL.

1/2/13

Consulting with the colleague that suggested the ID of a post/page showing, what he meant was in the “front end”, not in the edit or admin pages. Right now he’s inserting a bit of code to get that, but it would be nice not to have to do that.

1/4/13

Installed plugin “Notification Bar” (http://wordpress.org/extend/plugins/wordpress-notification-bar/changelog/) to see how it works. It places a bar at the top of all pages. it should give me a clue towards how to add information to any part of a site.

Also downloaded his first plugin – wanted to find something simpler and look at the code to learn from. http://wordpress.org/extend/plugins/wp-yui-menu/

1/5/12

Tonight’s mandate:

1. Start reading the book Professional WordPress Plugin DevelopmentProfessional WordPress Plugin Development“, by Williams, Richard, Tadlock.

2. Experiment with adding settings. This page looks like a good starting guide: http://codex.wordpress.org/Adding_Administration_Menus

So we want to add something in the admin menu. This page talks about how to do it:

http://codex.wordpress.org/Plugin_API/Action_Reference/admin_menu

The example given uses:

add_action( 'admin_menu', 'my_plugin_menu' );

which I’ll change to:

add_action( 'admin_menu', 'report_menu' );

http://codex.wordpress.org/Function_Reference/add_options_page

From looking at a couple of pages (searched “wordpress options vs. settings) that Options is the old way, and settings are a newer way. The book suggests Settings is more secure.

Checked out this article about writing a super simple plugin – for those bits of code you don’t want to put in your theme. Themes change but you can always re-use a plugin.

http://wpmu.org/how-to-create-your-own-super-simple-wordpress-plugins/

The blog author also mentioned testing code by putting it in the functions.php file.

Similarly, the book makes the point that plugins are a good alternative to hacking the core files. This reminds me of the advantage of child themes: updates will not override the changes you made.

This article covers the code for adding the login/out menu:

http://vanweerd.com/enhancing-your-wordpress-3-menus/#add_login

Learned from the book that it’s important to name plugin files, functions and variables with a prefix to help make them unique. So: “ep_wr_” prefix stands for “Eric Platt WordPress Reports”. These prefixes are important in order to avoid conflicts with other WP functions, etc.

1/6/13

Created a file for testing code, as suggested by the book:

<?PHP
// Load the WordPress Environment
// define ('WP_DEBUG', true); /* uncomment for debug mode */
require('./wp-load.php');
// require_once ('./wp_admin/admin.php'); /* uncommet for is_admin() */ 
?>
<pre>
	<?php
	echo "***** WORDPRESS ENVIRONMENT IS LOADED *****<br /><br />";	
	/* test stuff here */
	var_dump( is_admin() );

	?>
</pre>

…which made me curious about the loading of the WordPress environment. Did a Google search on “wordpress order of loading” and came up with this:

(from http://www.rarst.net/images/wordpress_core_load.png)

And these articles:

http://codex.wordpress.org/Query_Overview

http://humanshell.net/2011/08/14/wordpress-initialization/

Looked into creating an options or settings ability, but it’s more complex than expected, and is farther into the book, so am going to wait before attempting that.

Experimented with the test.php file and used it to try out the functions the chapter was talking about, such as:

    echo plugin_dir_path(_FILE_)
	echo plugins_url()
	echo includes_url()
	echo content_url()
	echo admin_url()
	echo site_url()
	echo home0_url()

Finished Chapter 2 in the book.

1/8/’13

Experimented with Action Hooks to place the same info bar in the front end. Tried:

add_action( ‘wp_head’, ‘ep_wr_echoReport’);
add_action( ‘wp_head’, ‘ep_wr_report_css’);

It does insert the info, but the jQuery doesn’t work, and the header gets expanded.

1/9/’13

Clear explanation of the difference between Actions and Filters:

http://wordpress.stackexchange.com/questions/1007/difference-between-filter-and-action-hooks

Looked into Filter Hooks. Created a plugin with a simple filter to test.

Used this page as a guide: http://codex.wordpress.org/Plugin_API/Filter_Reference/the_content

<?php
/*
Plugin Name: Test Filters
Plugin URI: http://devtegrity.com/
Description: Testing how to use filters and other functions
Version: 0.1 – 1/9/'13
Author: Eric Platt
Author URI: http://devtegrity.com
License: GPL2
*/

add_filter( 'the_content', 'my_the_content_filter', 20 );
add_filter( 'the_title', 'my_the_title_filter', 20 );
/**
 * Add some text to the beginning of every post page.
 *
 * @uses is_single()
 */
 function my_the_content_filter( $content ) {

 	if ( is_single() )
 		// Add the information to the beginning of each post
 		$content = sprintf('TEST filter for the_content %s', $content);
 	 	// Without formatting character %s (string) it will just output test string and not content;
 		// without $content it will show nothing.

 		return $content;
 }

 function my_the_title_filter ( $content ) {
 	$ep_wr_postID = ep_wr_getPostID();

 		// Add the information to the beginning of each title
 		// $content = sprintf('<span style="font-size: 0.5em"> TEST filter for the_title </span> %s', $content);
 	 	// Without formatting character %s (string) it will just output test string and not content;
 		// without $content it will show nothing.
 		// Simpler way to do it, and add to the end: use the PHP concatenating assignment operator ('.='), which appends the argument on the right side to the argument on the left 
 		$content .= '<span style="font-size: 0.4em; font-style: italic"> POST ID= '. $ep_wr_postID. '</span>' . "\n";

 		return $content;
 }

 function ep_wr_getPostID() {
   global $post;
  	$ep_wr_post_id = $post->ID;// Set a property in the $wp_query object called post and put it into $post
	return $ep_wr_post_id; 			
  }

There are hooks for the head and footer, but what about the body?
Turns out other people have had the same question. Here’s one thread:
http://stackoverflow.com/questions/3581510/wordpress-hook-directly-after-body-tag

Following the leads, this fellow in the UK says he has a solution. First he says “…use wp_head to add the following bit of script:

function DST(url) // remove the url variable here if you want inline, not external, script
{
   var s = document.createElement(‘script’);
   s.type=’text/javascript’;
   s.src= url; // this is optional if you want to link to an external script file
   s.text=’alert("hello there");’; // and this is optional if you want inline script
   document.getElementsByTagName(‘body’)[0].insertBefore(s,document.getElementsByTagName(‘body’)[0].firstChild);
}

http://www.maltpress.co.uk/2010/10/wordpress-injecting-code-after-the-body-tag-for-plugins
http://www.denisvlasov.net/129/javascript-prependchild/

1/10/’13
Tried this bit of code to add a login/logout menu:

//Add login/logout link to navigation menu
	function add_login_out_item_to_menu( $items, $args ){
	//change theme location with your them location name
		if( is_admin() ||  $args->theme_location != 'primary' )
			return $items;
		$redirect = ( is_home() ) ? false : get_permalink();
		if( is_user_logged_in( ) )
			$link = '<a href="' . wp_logout_url( $redirect ) . '" title="' .  __( 'Logout' ) .'">' . __( 'Logout' ) . '</a>';
		else  $link = '<a href="' . wp_login_url( $redirect  ) . '" title="' .  __( 'Login' ) .'">' . __( 'Login' ) . '</a>';
		return $items.= '<li id="log-in-out-link">'. $link . '</li>';
}
add_filter( 'wp_nav_menu_items', 'add_login_out_item_to_menu', 50, 2 );

(from: https://xparkmedia.com/2012/04/add-login-logout-link-menu/)
Tried putting it in my test.php file, but that didn’t work. So tried it in the functions file as suggested in the article and that does work.

1/17/13

Working on being able to show code un-munged in blog posts like this.

Tried plugin preserved HTML Editor Markup.

Finally went back and read the web page for the Crayon Syntax Highlighter plugin.
http://ak.net84.net/projects/crayon-syntax-highlighter/
The whole saga can be read about here:
http://www.facebook.com/groups/advancedwp/permalink/468990756496477/

1/19/13

Dear Webhero Support,

I’m doing a bit of development work and have been testing the WordPress mail function wp_mail(), but have not been able to get it to work. Same story for the PHP mail() function. My script is at:
http://www.devtegrity.com/test_email.php
Is there a server setting that needs to be changed to allow these to work?

Thank You

1/20

Got an email back:

"PHP mailing scripts require a php.ini file be created and placed in the folder above public_html to work correctly. I've uploaded this file for you and specified the k9saver@gmail.com you have in the test_email.php file. (You can change the email to whatever you need though.) This should allow the scripts to work."

He had my email address wrong. And it also didn’t work. Here’s the contents of the file:

sendmail_path = “/usr/local/safe/bin/sendmail -t -i -F platt.eric@gmail.com -f platt.eric@gmail.com”

Update: 2013-01-20 07:21 PM
Got an email back from support, after I noted that it didn’t work:
When I checked everything out again I believe I found the issue. It looks like there was some bad formatting in the php.ini I uploaded, the quotations were not standard and were most likely causing it not to be read correctly. Sorry for the confusion, that was completely an error on my part.

sendmail_path = "/usr/local/safe/bin/sendmail -t -i -F platt.eric@gmail.com -f platt.eric@gmail.com"

Turns out the mail was being blocked – by Google I guess – and was in the spam folder in Google mail:
"1] Our system has detected an unusual rate
of 550-5.7.1 unsolicited mail originating from your IP address. To protect
our 550-5.7.1 users from spam, mail sent from your IP address has been
blocked. 550-5.7.1 Please visit..."

Idea: to take learning forward, combine doing something with filter hooks and custom post data, as preparation for doing a mail function for that Digithrive client.

1/30/’13
Tried to activate WP Report and got error:
Fatal error: Cannot redeclare ep_wr_getpostid() (previously declared in /var/www/de/devtegrity.com/public_html/wp-content/plugins/ep_wr_test_filters.php:44) in /var/www/de/devtegrity.com/public_html/wp-content/plugins/ep_wr_report.php on line 59

Which means I’ll have to change the name of the function and variables in ep_wr_test_filters so they don’t conflict with WP Report. I just copied them over, so that’s they have the exact same name.

Some interesting ideas from the book “Professional WordPress Development”:
• Do a multi-site WP with different content for testing themes.
• Set up a local server with more than one version of WP for testing plugins.

1/31/13
Fixed a couple of bugs in WP Report plugin. WP was reporting that a variable didn’t exist: $ep_wr_counter. It was being used in a loop. So I set it to zero at the beginning of the function:
$ep_wr_counter = 0;
Noticed that the drop-down was pushing elements out of the way in the front end (and back). Tried changing position: relative to absolute in .msg_body. Worked.

Also tested out the change to Test Filters plugin – renamed all functions so they didn’t use “ep_wr_”, because one of them was also being used by WP Report. Worked: Now both plugins can be run at the same time.

Created a Custom Dashboard Widget (http://www.wpbeginner.com/wp-themes/how-to-add-custom-dashboard-widgets-in-wordpress/) by adding this code to the end of the functions.php file.

add_action('wp_dashboard_setup', 'my_custom_dashboard_widgets');

function my_custom_dashboard_widgets() {
	global $wp_meta_boxes;
	wp_add_dashboard_widget('custom_help_widget', 'Theme Support', 'custom_dashboard_help');
}

function custom_dashboard_help() {
echo '<p>Welcome to Custom Blog Theme! Need help? Contact the developer <a href="mailto:platt.eric@gmail.com">here</a>. For WordPress Articles visit: <a href="http://www.devtegrity.com" target="_blank">Devtegrity.com</a></p>';
}

The widget looks like this:

 

 

 

 

 

 

 

Resources:

http://codex.wordpress.org/Writing_a_Plugin

http://codex.wordpress.org/Plugin_API

http://codex.wordpress.org/Function_Reference/add_action

http://codex.wordpress.org/Plugin_API/Action_Reference

http://codex.wordpress.org/Adding_Administration_Menus

http://wordpress.tv/2013/01/18/justin-foell-building-your-first-plugin/

Theme File Execution Hierarchy:

http://wp.tutsplus.com/tutorials/the-wordpress-theme-files-execution-hierarchy/

Hooks Database:

http://adambrown.info/p/wp_hooks

The book “Professional WordPress Plugin Development“, by Williams, Richard, Tadlock.

PHP:

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

Content is King!

“Content, content, content!” is what I say to people who area trying to figure out what to do with a website – to make it popular, worth visiting. But is it worth visiting?  For people or the search engines? More and more, Google (an no doubt other search engines) are making real, worthwhile content the…

Photoshoot Journal: Journey to Otay Lakes

I was recently hired to photograph the Otay Lakes area in South San Diego County, for a client wanting some photos on their website of the area their center is located in. (Otay Lakes Surgery Center). And on-site photoshoot is always an adventure, and one I look forward to. I relish seeing a new place…