Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

August 15 2013

13:00

Fluid Mask 3: Luxurious Image Masking Tool Given Away


  

Masking images is a tedious task. Who would have thought that this bride decides to want a green background when we just shot a series of photos in front of a blue background? Who would have thought the photographer would leave so early? Now it’s your turn, again. Does this remind you of the smoke scenery from last year, where you were also asked to exchange the background? What do these people think? Photo manipulation is as easy as one-two-three? Well, they may have been wrong to think so in the past. But today, we’ve got Fluid Mask. And with Fluid Mask, it actually is as easy as one-two-three. You need not tell them, though. Let’s keep it a secret…

June 11 2013

09:30

Developer Thoughts: Four Lessons We Learned While Creating our First WordPress Plugin


  
wordpress-hate-main Building our first plugin wasn’t an entirely smooth process - anyone thinking of doing something similar should consider several things before they get started. Below are the lessons we picked up.
Sponsored post
soup-sponsored
05:36
Reposted bySchrammelhammelMrCoffeinmybetterworldkonikonikonikonikoniambassadorofdumbgroeschtlNaitliszpikkumyygittimmoejeschgeKameeel

August 23 2012

13:00

Create an Author Comments Feed in WordPress

In recent years blogs have become so popular that and they’re one of the most common ways people get their daily dose of information. It’s not possible for a single person to provide quality content everyday. As a result, major websites are accepting  guest authors to provide quality content on a regular basis.

Authors play a vital role in these multi-author blogs since they are responsible for providing up-to-date content for their readers. Once a post is published, the author has to respond to comments, fix the issues and update the content according to the latest trends. As an Author, it is important to respond to user comments quickly. When a comment is made, only the administrator gets the notification email to approve the comments. But there is no default functionality to notify the author.

Authors have to view comments of each post regularly and I can tell you that is very hard if you have written a large number of posts. In this tutorial I am going to ease this task by creating an author comments feed for the comments of all posts written by a single author. Then you will be able to view all the comments in one place. So Lets get started.

Plugin Download

Creating The Author Comments Plugin

Although we can create our functionality in the functions.php file of the theme, it’s always recommended to create an independent plugin for custom functionality. So let’s create a folder called Author-Comments-Feed inside the wp-content/plugins folder and insert the following code to index.php file. It is used to provide information about the plugin.

/*
  Plugin Name: Author Comments Feed
  Plugin URI: http://innovativephp.com/
  Description: Generate RSS feed for comments on all the posts of a specific author.
  Version: 1.0
  Author: Rakhitha Nimesh
  Author URI: http://innovativephp.com/about/
  License: GPLv2 or later
 */

Now you will be able to see our plugin in the plugin list on the admin dashboard. So let’s move onto adding our RSS feed.

Adding Custom RSS Feed

WordPress provides a default set of RSS feeds for posts, comments, categories etc. Also we are allowed to create custom RSS feeds using the add_feed function. So let’s add our Author RSS feed.

function add_author_comments_feed() {
    global $wp_rewrite;
    add_feed('wp_author_comments', 'wp_author_comments_feed');
    add_action('generate_rewrite_rules', 'author_comments_rewrite_rules');
    $wp_rewrite->flush_rules();
}

add_action('init', 'add_author_comments_feed');
  • First we add add_author_comments_feed function to be called after WordPress has finished loading using the init action.
  • Then we add our feed using the WordPress add_feed function. We have to pass 2 parameters to this function.
  • First parameter will be the type of feed. I have named it wp_author_comments. Default feed types are RSS1, RSS2, ATOM.
  • Second parameter is the name of the function which is used to generate the RSS feed.
  • Then we have to define custom permalinks for the RSS feed. I have added author_comments_rewrite_rules function using the generate_rewrite_rules filter. I’ll explain these functions in the next section.
  • Finally we flush the rewrite rules structure using $wp_rewrite->flush_rules method to refresh the rewrite rule cache.

Lets move onto creating custom rewrite rules for Author Comments Feed.

Define Custom Rewrite Rules

If you are using the default URL structure of WordPress (using query strings), you don’t need to worry about this section. This section is essential if the site uses a custom permalink structure. So lets take a look at our author_comments_rewrite_rules function.

function author_comments_rewrite_rules($wp_rewrite) {

    $new_rules = array(
        'feed/(.+)/(.+)' => 'index.php?feed=' . $wp_rewrite->preg_index(1)
    );
    $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;

}
  • $wp_rewrite object has all the information about the rewrite rules and it will be passed to the author_comments_rewrite_rules function by default.
  • First we prepare the new rules for the custom feed. In our URL we need feed type and author username. So we define it as feed/(.+)/(.+) and redirect to index.php with feed parameter.
  • Finally we add our new rules to the original rules structure.

Now we are ready with our custom rewriting rules and its time to create the Author Comments Feed.

Generating Author Comments Feed

I am going to use “Universel Feed Writer class” library for generating RSS feed. You can download it here.

Once downloaded add the FeedWriter.php file and FeedItem.php file to your plugin directory.

Then make sure to include FeedWriter.php file in the top of the index file. Also we need slight modification to the autoload function in the downloaded library. Following code shows the default autoload function in the library.

function __autoload($class_name){
    require_once $class_name . '.php';
}

The code above will try to autoload every class in WordPress as well and will generate errors. So modify the above function with the following code to only autoload the classes related to the library.

function __autoload($class_name){
     if($class_name == 'FeedItem'){
         require_once $class_name . '.php';
     }
}

Now lets take a look at our wp_author_comments_feed function which generates the RSS feed.

function wp_author_comments_feed() {

    global $wpdb;

    $username = isset($_GET['auth']) ? $_GET['auth'] : array_pop(explode("/", $_SERVER['REQUEST_URI'])) ;

    $user = get_user_by('login', $username);

    $sql = "SELECT $wpdb->posts.guid,$wpdb->posts.post_title,$wpdb->comments.comment_author,
$wpdb->comments.comment_author_email,$wpdb->comments.comment_date,
$wpdb->comments.comment_content FROM $wpdb->posts inner join $wpdb->comments
on $wpdb->posts.ID=$wpdb->comments.comment_post_ID WHERE
$wpdb->posts.post_author=".$user->data->ID." and $wpdb->posts.post_status='publish'";

    $numComments = $wpdb->get_results($sql);

    $TestFeed = new FeedWriter(RSS2);

    $TestFeed->setTitle('Author Comments Feed of '.$user->data->display_name);
    $TestFeed->setLink('http://www.1stwebdesigner.com');

    foreach ($numComments as $key => $comment) {

        //Create an empty FeedItem
        $newItem = $TestFeed->createNewItem();

        $description = "Comment Author Name : $comment->comment_author <br/>
				Comment Author Email : $comment->comment_author_email <br/>
				Comment : $comment->comment_content <br/>";

        //Add elements to the feed item
        $newItem->setTitle("New Comment on " . $comment->post_title);
        $newItem->setLink($comment->guid);
        $newItem->setDate($comment->comment_date);
        $newItem->setDescription($description);

        //Now add the feed item
        $TestFeed->addItem($newItem);
    }

    $TestFeed->genarateFeed();exit;
}
  • First we have to get the author’s username using the URL. We have to consider both default and custom permalink structures here.
  • In default one URL will look like ?feed=wp_author_comments&auth=username. so we first check if the username is available in query string using the $_GET['auth']
  • We get the username for the custom permalinks by using array_pop(explode(“/”, $_SERVER['REQUEST_URI'])) which splits the URL components.
  • Then we get all the author information by passing username to get_user_by function.
  • Next we get all the comments for the posts written by the author using the join on posts and comments tables. Now we have an array of all the comments for all the posts written by the author.
  • Next we initialize the FeedWriter and set the title and link of the RSS feed. You can customize these values according to your preference.
  • Then we loop through each comment and sets the information for the feed by using setTitle, setLink, setDate, setDescription methods. Then we add items to the RSS feed using addItem function at the end of each loop.
  • Finally we call the genarateFeed function to create the RSS feed and print it to the browser.

Now we have the Author Comments Feed ready. Every author can access the comments feed using ?feed=wp_author_comments&auth=username or /feed/wp_author_comments/username depending on the permalink structure.

It’s important to notice that this plugin will only work with WordPress default comment system which stores the comments on wp_comments table. Plugin will not work with custom commenting systems like DISQUS.

Now authors have their own comment feed and the problem of responding to latest comments is solved. Lets see how we can improve this by using IFTTT.

Getting Email Notifications Using IFTTT

Even though we have a comment feed, it takes time to log into your RSS reader and look for the new comments on your posts. So lets see how we can use IFTTT services to get an email directly to your inbox when the comment feed is updated. First create an account in IFTTT.com and log into your account.

Then click on the Create button in the dashborad and you will get the following screen.

Create Recipe

Click this and you will get a list of channels in the bottom of the page as shown below.

Choose Incoming Channel

Choose Feed and you will get the next screen as following.

Choose a Trigger

Choose New Feed Item and you will be directed to enter the Feed URL.

Complete Incoming Trigger Fields

Enter the URL of the feed and you username in the format which I mentioned in earlier section and click Create Trigger button to get the following screen.

Choose Outgoing Channel

Click that and choose a channel as we did before. Since we want to get an email, its better to select Gmail from the list. You will be directed to the following screen.

Choose Outgoing Action

Click Send an Email to get to the following screen.

Create Action

Enter your email address and customize the content according to your preference. Finally click the Create Action button.

Now every time the feed is updated you will receive an email to your gmail account.This method will save you a lot of time in responding to comments. Hope you enjoyed it and feel free to share your comments.

January 02 2012

18:30

Introducing Nettuts+ Fetch

In addition to producing various helpful apps for web developers, in 2012, we’ll also be commissioning and releasing smaller plugins and extensions. Today, I’d like to announce the first entry in this initiative: “Nettuts+ Fetch” – a Sublime Text plugin.


The 20 Second Example


Choose 720p for a clearer picture.

The Dilemma

Let’s say that you’re a fan of Normalize.css. Perhaps, you download it and save it to a snippet, or store the stylesheet, itself, in an assets folder. That way, for future projects, you only need to copy and paste.

The only problem with this method – as we’ve all discovered – is that, if a few months have passed, it’s more than possible that the asset (in this case, Normalize.css) will have been updated by the creator. So your options are to either use the, now, out-dated version of Normalize, or, once again, return to the GitHub page and pull in a fresh copy. This all seems tedious.


The Solution

Created by Weslly Honorato, Nettuts+ Fetch is the solution to our dilemma.

I thought to myself: “What if there was a plugin that would automatically pull in the latest copy of a file, simply by typing a keyboard shortcut. It’ll perform a curl request to your specified URL (saved away for future use), and allow you to rest assured that, for all new projects, you’re using the latest copy of a particular asset.

Created by Weslly Honorato, Nettuts+ Fetch is the solution to our dilemma.


Installation Instructions

Nettuts+ Fetch

While you can manually download Nettuts+ Fetch from GitHub, the easiest way to set it up is through Package Control (which all ST2 users should be using). Once you’ve installed package control, press ctrl+shift+p (Windows, Linux) or cmd+shift+p (OS X), and type “Package Install.” Next, search for “Nettuts+ Fetch,” press enter, and you’re done. Simple.


Usage

You’ll only use two commands, when working with Fetch. First, we need to save some file references. Again, bring up the command palette, and search for “Fetch.” For now, choose “Manage Remote Files.”

Manage Remote Files

What’s great about Sublime Text 2 is that configuration is incredibly simple. To assign references to online asset files, we only need to create an object, like so (don’t worry; one will be pre-populated for you, after installation):

So, to pull in the latest copy of jQuery (if you don’t want to use a CDN):

{
	"files":
	{
		"jquery": "http://code.jquery.com/jquery.min.js"
	}
}

Packages

Even better, I can pull in entire packages, or zip files. What if we want to start a new project, using HTML5 Boilerplate? In that case, we add the reference to the “packages” object.

{
	"files":
	{
		"jquery": "http://code.jquery.com/jquery.min.js"
	},
	"packages":
	{
		"html5-boilerplate": "http://github.com/h5bp/html5-boilerplate/zipball/v2.0stripped"
	}
}

Fetch, Boy

Now that we have a package and script saved (add as many as you like), we can pull them in by using the Fetch command. Pull up the command palette – ctrl+shift+p (Windows, Linux) or cmd+shift+p (OS X) – type “Fetch,” and make your selection.

Choose HTML5 Boilerplate from the list, give it a few seconds, and, bam, you’re ready to go with the latest release.

Pretty sweet, huh? I hope you like it! Thanks again to Weslly Honorato for building it for us.


December 16 2011

10:00

Manage All Your WordPress Sites From One Place: Meet ManageWP

For a kickoff we’ve prepared a review of a really neat and useful service some of you guys will be keen on. Those of you who manage more than one WordPress blog will be more or less familiar with the management problems multiple blogs can create. Installing new plugins, updating platforms, keeping an eye on the posts – it’s getting pretty inconvenient if you’ve got couple of active blogs.

Yes, some of you might have already figured out what kind of service we’re writing about here. ManageWP is a service that allows you to manage all your WordPress websites from one single dashboard. What does it mean?

Lets quickly run over the main features:

  • Firstly, that means that you no longer have to remember all logins and passwords for your sites or keep them in long spreadsheets. With ManageWP dashboard you can access all your websites with one click.
  • Performing an upgrade of WordPress, plugins and themes across all of your sites is easy as clicking one ‘Upgrade all’ button. You can also install plugins and themes to multiple sites at once, from a variety of sources (your favorites list, WordPress.org, your computer or any URL).
  • You can backup all your sites from ManageWP dashboard at any time or restore a previous backup. ManageWP can backup both your entire website or just the database. You can also set automatic scheduled backups.
  • ManageWP allows you to set up a new, fully loaded, WordPress site in minutes. Or use ManageWP’s clone tool to clone any of your existing sites from one domain, subdomain or folder to another.
  • With all sites under one roof, doing bulk operations becomes easy. Whether you want to post an article to multiple sites, manage your blogroll links or add users, ManageWP allows you to do it effortlessly across any number of sites at once.

How does it work? Do you have to provide them with all your passwords? The answer is no. Access to your site is governed by the ManageWP Worker plugin that you install directly onto your blog. That means that the only password ManageWP stores is the one needed for their central dashboard. So lets get started and take a deeper look into this service.

Features

Dashboard

Managewp-dashboard-fresh-successful-startups-review

Once you’ve installed the plugin and linked your website with ManageWP you can access all the features it offers. The dashboard is clean and easy to use. Plus it looks just like your casual WordPress dashboard so you don’t have to worry about adapting to a new and unfamiliar platform.

In the main view you can see which plugins or themes have an update available, below there are post revisions aka post autosaves and spam comments. You can also view the recent comments and posts. In the top right there is a pageview statistics graph and scheduled backups below it.

Manage Plugins & Themes

Managewp-plugins-fresh-successful-startups-review

ManageWP dashboard allows you to instantly and simultaneously install themes or plugins for all of your websites. You can also opt to Activate plugins after upload. Looking through all the plugins is also made easy. In my opinion, the only drawback is the plugin horizontal layout so you have to scroll the window quite far if you’ve got a lot of plugins installed.

Backup

Managewp-backup-fresh-successful-startups-review

With ManageWP, you can set up scheduled backups to Amazon S3, Dropbox, your own server, any external FTP or an email address for all of your blogs with just a few clicks. You can choose between daily, weekly or monthly backups. Note – this feature is only available for the professional and business pricing plan.

Migrating/cloning sites.

Managewp-clone-fresh-successful-startups-review

This feature comes in handy if you need to setup a new network of identically modified websites. The theme and all plugins are installed automatically so you don’t have to spend time setting up every blog manually.

Bulk Actions

ManageWP allows you to bulk add/export websites, create new pages, posts and links for all of your websites.

Managewp-bulk-post-fresh-successful-startups-review

It’s pretty clear with the pages and posts – although I don’t see a good reason why one would like to publish the same post on several blogs, the function does it’s job. Again you’re given the default WordPress text editor so there’s nothing unfamiliar to master.

Managewp-bulk-user-fresh-successful-startups-review

The Bulk add users feature is bloody useful if you’re willing to add a writer for a set of blogs. You can find this feature under the Users section.

Note – all the bulk features are only available for professional and business pricing plan.

Self-hosted version

ManageWP also offers self-hosted version which allows you to run the service on your own dashboard. Self hosted allows you to have an unlimited number of blogs, host everything on your server and add your own features. It’s created for companies and organizations managing hundreds or even thousands of websites and is currently available only as Enterprise license.

Pricing

ManageWP will be offering three pricing plans where the price then depends on the number of websites you’ll manage (you can choose from a range between 10 and 500). The pre-order is launching on December 6th. All users that sign up now will receive a 30% life-time discount on any hosted service plan that they pre-order for as long as they maintain their service.

  • 30 day free trial so you can test the service before paying for it.
  • Free plan which allows you to use the Standard features for up to three (five, if you refer some friends) websites.
  • Annual plans, and you will get two months free when you sign up for these.

Below you can see the pricing plans for 10, 100 and 500 websites.

10 websites

  • Standard: $7/month
  • Professional: $21/month
  • Business: $42/month

100 websites

  • Standard: $40/month
  • Professional: $120/month
  • Business: $240/month

500 websites

  • Standard: $70/month
  • Professional: $210/month
  • Business: $420/month

Interview

Since this series focuses on the startups we wanted to ask a couple of questions to the founder of ManageWP Vladimir Prelovac.Vladimir Prelovac is the the CEO of Prelovac Media, an internet company located in Belgrade, Serbia. Besides ManageWP he’s also written a book on WordPress plugin development and created other stunning services and plugins.

1. There aren’t many alternatives who can compete with ManageWP. How did you come up with the idea of ManageWP?

As with most good ideas, it was a stroke of luck and a hint of opportunity. A friend of mine was rambling about how he had trouble managing his blogs, and I suddenly realized there is nothing like that available for WordPress, which is, after all, the world’s biggest internet publishing platform. The world needed something like ManageWP, so I decided it was time to make it.

2. As far as I understand ManageWP began in 2010. Why did it take so long to finish beta testing and establish a fully functional service?

ManageWP is an extremely complex piece of software. What makes it unique is that we really tried to make it run smoothly on literally thousands of different server configurations that WordPress would run on. That was our biggest challenge. Scalability was also an important focus for us — some of our users are managing thousands of blogs. But knowing that ManageWP can load data from 1800 websites in less than two minutes… it makes it all worth it.

There is also a list of spectacular features that we are pushing to integrate into ManageWP. Some startups, for example, are satisfied with only offering backup solutions for WordPress. But that functionality is only a tiny piece of the overall picture. Backup features are critical — and something we pride ourselves in offering — but it is only one piece of the 23 major features currently offered by ManageWP, with many more on the way. And with all the great ideas coming in from our beta users, we know that the value we can provide will continue to grow.

Another thing is that we had to ensure that ManageWP would work with services that WordPress users already deeply value. That’s why ManageWP now integrates with Google Analytics and AdSense. And that’s why we already have plans in place to integrate with SEO and uptime monitoring tools in the near future.

And then there is the fact that WordPress is constantly evolving. Adjusting to all the changes is a challenge unless you are willing to work hard to adjust to those changes. Thankfully, our team put in the effort to adapt. So that’s why it all took almost a year and a half to arrive at this point. (And the ride is not over yet!)

Ultimately, our goal is to create a dashboard so useful, so powerful that people will no longer need to log into their WordPress websites or other services. They will be able to log into ManageWP, and everything that the user needs to effectively manage their WordPress sites will be all right there at the user’s fingertips.

Managewp-2010-fresh-successful-startups-review

Above you can see a screenshot from Wayback Machine with the ManageWP website in 2010.

3. You’ve established a flexible and nice scheme where instead of following a strict milestone schedule the users themselves suggest the ideas you then consider. How did you come up with this method and has it brought the desired results?

Yes! I believe this is one of our strengths at ManageWP. Many of our features were suggested by our users, and that makes it a much more personalized experience for them and for us. After all, nobody could ever have a perfect vision of a product (except maybe Steve Jobs), so it was very important that we listened to our users early on in the development process. We already have around six or seven different ways for users to send us feedback, and I read all of it. The best ideas are sent off to the team for development.

Managewp-ideas-fresh-successful-startups-review

Above you can see a screenshot from ManageWP Google group where users can suggest ideas which then are sent for consideration.

4. Since our series is about successful and fresh startups could you comment on ManageWP from this perspective? How has it grown as a project?

There are different ways to measure the success of a startup. At ManageWP, and from the feedback we have received, it would seem that we created a truly useful service that solves a problem that many people share. Some of our users were excited to learn when we intended to charge for ManageWP, but for the past 12 months, all we wanted to do was focus on creating a genuinely useful product.

And I think that is the most important thing — in order to keep the team passionate and the users interested, you need to have a great product.

5. Your blog says that the number of websites managed by ManageWP has hit 50 000. How do you feel about these results and what are predictions for the future?

Well, looking at numbers like these is always exciting. We hit 50,000 websites near the end of September, but we now manage over 80,000 WordPress blogs. So, when you put it into that perspective, you get really excited as you can see that your product is making a small but measurable change in how the internet works.

Somebody once said that the best way to predict the future is to invent it.

By having a clear vision of where we want to go and by keeping our customers happy, inventing the future is exactly what we are doing. It also helps when we are working with a strong and thriving publishing platform in WordPress. So, all things considered, I am very positive about our future.

Managewp-50k-fresh-successful-startups-review

Above you can see a screenshot with the exciting announcement.

6. Could you share some of your tips/business principles for others out there willing to make a successful startup?

There are couple of principles that I believe will make any startup’s journey easier:

First is that you need to have a cool product, one that you strongly believe in and you will want to use on your own. This also makes it so much easier to justify putting most, if not all, of your own time, money, and heart into it. You have to realize that there will be many hurdles along the way, as with all things in life, so you better have an idea of what you are doing and why you are doing it.

Second is to launch the beta as soon as possible. This allows you to start listening to your users and getting feedback. They will give great ideas on how to improve your product… for free!

Third is to not create a startup that relies on external funding to succeed. We are completely bootstrapped, which most likely forced us to create a significantly better product than we might have if we were basking in investment money. It motivates you to perform.

Fourth is the speed — making efforts to optimize your application and interface like crazy. Users have never been as impatient as they are today. Also, intuitiveness: the less the users needs to think, the better. You really need to watch other people use your product. You will be surprised by what you will discover.

Do the above things, and people will be drawn to your efforts and will help you to succeed.

7. Additional information

We are launching the pre-order on December the 6th. All users that sign up now will receive a 30% life-time discount on any hosted service plan that they pre-order for as long as they maintain their service, so come check us out! Finally, ManageWP is set to launch in early January.

Conclusion

ManageWP indeed is an amazing and one of the most useful services for WordPress. It’s also a great example of a fresh startup success story. You should definitely check out the free trial if you are running multiple WordPress websites. We’d be glad to hear your feedback and personal experiences. Stay tuned and wait for the next hot startup story.

Little explanation, what we’re doing here

This is something new we are trying out here at 1WD. We are searching for new startups, services we really enjoy and want to share with our readership! The idea is to give better visibility to some outstanding startups and give you a good understanding of what they do and why we think they deserve your attention. Also – we don’t earn anything from these reviews, we just find what we love and review it honestly in detail. When we can, we will always interview the people behind the startup, so you can learn from them, and they can share their passion and story.

I think this new idea and a little shift in focus here at 1WD will be really beneficial for You and feel free to critique what you didn’t enjoy in this article, what you want us to review next and tell us what we did right and if you want more articles like this!

We are very open and if you know about a cool service we could review – just write us in our contact form!

Dainis Graveris

November 14 2011

16:20

How to Create a Sublime Text 2 Plugin

Sublime Text 2 is a highly customizable text editor that has been increasingly capturing the attention of coders looking for a tool that is powerful, fast and modern. Today, we’re going to recreate my popular Sublime plugin that sends CSS through the Nettuts+ Prefixr API for easy cross-browser CSS.

When finished, you’ll have a solid understanding of how the Sublime Prefixr plugin is written, and be equipped to start writing your own plugins for the editor!


Preface: Terminology and Reference Material

The extension model for Sublime Text 2 is fairly full-featured.

The extension model for Sublime Text 2 is fairly full-featured. There are ways to change the syntax highlighting, the actual chrome of the editor and all of the menus. Additionally, it is possible to create new build systems, auto-completions, language definitions, snippets, macros, key bindings, mouse bindings and plugins. All of these different types of modifications are implemented via files which are organized into packages.

A package is a folder that is stored in your Packages directory. You can access your Packages directory by clicking on the Preferences > Browse Packages… menu entry. It is also possible to bundle a package into a single file by creating a zip file and changing the extension to .sublime-package. We’ll discuss packaging a bit more further on in this tutorial.

Sublime comes bundled with quite a number of different packages. Most of the bundled packages are language specific. These contain language definitions, auto-completions and build systems. In addition to the language packages, there are two other packages: Default and User. The
Default package contains all of the standard key bindings, menu definitions, file settings and a whole bunch of plugins written in Python. The User package is special in that it is always loaded last. This allows users to override defaults by customizing files in their User package.

During the process of writing a plugin, the Sublime Text 2 API referencewill be essential.

During the process of writing a plugin, the Sublime Text 2 API referencewill be essential. In addition, the Default package acts as a good reference for figuring out how to do things and what is possible. Much of the functionality of the editor is exposed via commands. Any operation other than typing characters is accomplished via commands. By viewing the Preferences > Key Bindings – Defaultmenu entry, it is possible to find a treasure trove of built-in functionality.

Now that the distinction between a plugin and package is clear, let’s begin writing our plugin.


Step 1 - Starting a Plugin

Sublime comes with functionality that generates a skeleton of Python code needed to write a simple plugin. Select the Tools > New Plugin…menu entry, and a new buffer will be opened with this boilerplate.

import sublime, sublime_plugin

class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")

Here you can see the two Sublime Python modules are imported to allow for use of the API and a new command class is created. Before editing this and starting to create our own plugin, let’s save the file and trigger the built in functionality.

When we save the file we are going to create a new package to store it in. Press ctrl+s (Windows/Linux) or cmd+s (OS X) to save the file. The save dialog will open to the User package. Don’t save the file there, but instead browse up a folder and create a new folder named Prefixr.

Packages/
…
- OCaml/
- Perl/
- PHP/
- Prefixr/
- Python/
- R/
- Rails/
…

Now save the file inside of the Prefixr folder as Prefixr.py. It doesn’t actually matter what the filename is, just that it ends in .py. However, by convention we will use the name of the plugin for the filename.

Now that the plugin is saved, let’s try it out. Open the Sublime console by pressing ctrl+`. This is a Python console that has access to theAPI. Enter the following Python to test out the new plugin:

view.run_command('example')

You should see Hello World inserted into the beginning of the plugin file. Be sure to undo this change before we continue.


Step 2 - Command Types and Naming

For plugins, Sublime provides three different types of commands.

  • Text commands provide access to the contents of the selected file/buffer via a View object
  • Window commands provide references to the current window via a Window object
  • Application commands do not have a reference to any specific window or file/buffer and are more rarely used

Since we will be manipulating the content of a CSS file/buffer with this plugin, we are going to use the sublime_plugin.TextCommand class as the basis of our custom Prefixr command. This brings us to the topic of naming command classes.

In the plugin skeleton provided by Sublime, you’ll notice the class:

class ExampleCommand(sublime_plugin.TextCommand):

When we wanted to run the command, we executed the following code in the console:

view.run_command('example')

Sublime will take any class that extends one of the sublime_plugin classes
(TextCommand, WindowCommand or ApplicationCommand), remove the suffix Command and then convert the CamelCaseinto underscore_notation for the command name.

Thus, to create a command with the name prefixr, the class needs to be PrefixrCommand.

class PrefixrCommand(sublime_plugin.TextCommand):

Step 3 - Selecting Text

One of the most useful features of Sublime is the ability to have multiple selections.

Now that we have our plugin named properly, we can begin the process of grabbing CSS from the current buffer and sending it to the Prefixr API. One of the most useful features of Sublime is the ability to have multiple selections. As we are grabbing the selected text, we need to write our plug into handle not just the first selection, but all of them.

Since we are writing a text command, we have access to the current view via self.view. The sel() method of the View object returns an iterable RegionSet of the current selections. We start by scanning through these for curly braces. If curly braces are not present we can expand the selection to the surrounding braces to ensure the whole block is prefixed. Whether or not our selection included curly braces will also be useful later to know if we can tweak the whitespace and formatting on the result we getback from the Prefixr API.

braces = False
sels = self.view.sel()
for sel in sels:
    if self.view.substr(sels[0]).find('{') != -1:
        braces = True

This code replaces the content of the skeleton run() method.

If we did not find any curly braces we loop through each selection and adjust the selections to the closest closing curly brace. Next, we use the built-in command expand_selection with the to arg set to brackets to ensure we have the complete contents of each CSS block selected.

if not braces:
    new_sels = []
    for sel in sels:
        new_sels.append(self.view.find('}', sel.end()))
    sels.clear()
    for sel in new_sels:
        sels.add(sel)
    self.view.run_command("expand_selection", {"to": "brackets"})

If you would like to double check your work so far, please compare the source to the file Prefixr-1.py in the source code zip file.


Step 4 - Threading

To prevent a poor connection from interrupting other work, we need to make sure that the Prefixr API calls are happening in the background.

At this point, the selections have been expanded to grab the full contents of each CSS block. Now, we need to send them to the Prefixr API. This is a simple HTTP request, which we are going to use the urllib and urllib2 modules for. However, before we start firing off web requests, we need to think about how a potentially laggy web request could affect the performance of the editor. If, for some reason, the user is on a high-latency, or slow connection, the requests to the Prefixr API could easily take a couple of seconds or more.

To prevent a poor connection from interrupting other work, we need to make sure that the Prefixr API calls are happening in the background. If you don’t know anything about threading, a very basic explanation is that threads are a way for a program to schedule multiple sets of code to run seemingly at the same time. It is essential in our case because it lets the code that is sending data to, and waiting for a response from, the Prefixr API from preventing the rest of the Sublime user interface from freezing.


Step 5 - Creating Threads

We will be using the Python threading module to create threads. To use the threading module, we create a new class that extends threading.Thread called PrefixrApiCall. Classes that extend threading.Thread include a run() method that contains all code to be executed in the thread.

class PrefixrApiCall(threading.Thread):
    def __init__(self, sel, string, timeout):
        self.sel = sel
        self.original = string
        self.timeout = timeout
        self.result = None
        threading.Thread.__init__(self)

    def run(self):
        try:
            data = urllib.urlencode({'css': self.original})
            request = urllib2.Request('http://prefixr.com/api/index.php', data,
                headers={"User-Agent": "Sublime Prefixr"})
            http_file = urllib2.urlopen(request, timeout=self.timeout)
            self.result = http_file.read()
            return

        except (urllib2.HTTPError) as (e):
            err = '%s: HTTP error %s contacting API' % (__name__, str(e.code))
        except (urllib2.URLError) as (e):
            err = '%s: URL error %s contacting API' % (__name__, str(e.reason))

        sublime.error_message(err)
        self.result = False

Here we use the thread __init__() method to set all of the values that will be needed during the web request. The run() method contains the code toset up and execute the HTTP request for the Prefixr API. Since threads operate concurrently with other code, it is not possible to directly return values. Instead we set self.result to the result of the call.

Since we just started using some more modules in our plugin, we must add them to the import statements at the top of the script.

import urllib
import urllib2
import threading

Now that we have a threaded class to perform the HTTP calls, we need to create a thread for each selection. To do this we jump back into the run() method of our PrefixrCommand class and use the following loop:

threads = []
for sel in sels:
    string = self.view.substr(sel)
    thread = PrefixrApiCall(sel, string, 5)
    threads.append(thread)
    thread.start()

We keep track of each thread we create and then call the start() method to start each.

If you would like to double check your work so far, please compare the source to the file Prefixr-2.py in the source code zip file.


Step 6 - Preparing for Results

Now that we’ve begun the actual Prefixr API requests we need toset up a few last details before handling the responses.

First, we clear all of the selections because we modified them earlier. Later we will set them back to a reasonable state.

self.view.sel().clear()

In addition we start a new Edit object. This groups operations for undo and redo. We specify that we are creating a group for the prefixr command.

edit = self.view.begin_edit('prefixr')

As the final step, we call a method we will write next that will handle the result of the API requests.

self.handle_threads(edit, threads, braces)

Step 7 - Handling Threads

At this point our threads are running, or possibly even completed. Next, we need to implement the handle_threads() method we just referenced. This method is going to loop through the list of threads and look for threads that are no longer running.

def handle_threads(self, edit, threads, braces, offset=0, i=0, dir=1):
    next_threads = []
    for thread in threads:
        if thread.is_alive():
            next_threads.append(thread)
            continue
        if thread.result == False:
            continue
        offset = self.replace(edit, thread, braces, offset)
    threads = next_threads

If a thread is still alive, we add it to the list of threads to check again later. If the result was a failure, we ignore it, however for good results we call a new replace() method that we’ll be writing soon.

If there are any threads that are still alive, we need to check those again shortly. In addition, it is a nice user interface enhancement to provide an activity indicator to show that our plugin is still running.

if len(threads):
    # This animates a little activity indicator in the status area
    before = i % 8
    after = (7) - before
    if not after:
        dir = -1
    if not before:
        dir = 1
    i += dir
    self.view.set_status('prefixr', 'Prefixr [%s=%s]' % 
        (' ' * before, ' ' * after))

    sublime.set_timeout(lambda: self.handle_threads(edit, threads,
        braces, offset, i, dir), 100)
    return

The first section of code uses a simple integer value stored in the variable i to move an = back and forth between two brackets. The last part is the most important though. This tells Sublime to run the handle_threads()method again, with new values, in another 100 milliseconds. This is just like the setTimeout() function in JavaScript.

The lambda keyword is a feature of Python that allows us to create a new unnamed, or anonymous, function.

The sublime.set_timeout() method requires a function or method and the number of milliseconds until it should be executed. Without lambda we could tell it we wanted to run handle_threads(), but we would not be able to specify the parameters.

If all of the threads have completed, we don’t need to set another timeout, but instead we finish our undo group and update the user interface to let the user know everything is done.

self.view.end_edit(edit)

self.view.erase_status('prefixr')
selections = len(self.view.sel())
sublime.status_message('Prefixr successfully run on %s selection%s' %
    (selections, '' if selections == 1 else 's'))

If you would like to double check your work so far, please compare the source to the file Prefixr-3.py in the source code zip file.


Step 8 - Performing Replacements

With our threads handled, we now just need to write the code that replaces the original CSS with the result from the Prefixr API. As we referenced earlier, we are going to write a method called replace().

This method accepts a number of parameters, including the Edit object for undo, the thread that grabbed the result from the Prefixr API, if the original selection included braces, and finally the selection offset.

def replace(self, edit, thread, braces, offset):
    sel = thread.sel
    original = thread.original
    result = thread.result

    # Here we adjust each selection for any text we have already inserted
    if offset:
        sel = sublime.Region(sel.begin() + offset,
            sel.end() + offset)

The offset is necessary when dealing with multiple selections. When we replace a block of CSS with the prefixed CSS, the length of that block will increase. The offset ensures we are replacing the correct content for subsequent selections since the text positions all shift upon each replacement.

The next step is to prepare the result from the Prefixr API to be dropped in as replacement CSS. This includes converting line endings and indentation to match the current document and original selection.

result = self.normalize_line_endings(result)
(prefix, main, suffix) = self.fix_whitespace(original, result, sel,
    braces)
self.view.replace(edit, sel, prefix + main + suffix)

As a final step we set the user’s selection to include the end of the last line of the new CSS we inserted, and then return the adjusted offset to use for any further selections.

end_point = sel.begin() + len(prefix) + len(main)
self.view.sel().add(sublime.Region(end_point, end_point))

return offset + len(prefix + main + suffix) - len(original)

If you would like to double check your work so far, please compare the source to the file Prefixr-4.py in the source code zip file.


Step 9 - Whitespace Manipulation

We used two custom methods during the replacement process to prepare the new CSS for the document. These methods take the result of Prefixr and modify it to match the current document.

normalize_line_endings() takes the string and makes sure it matches the line endings of the current file. We use the Settings class from the Sublime API to get the proper line endings.

def normalize_line_endings(self, string):
    string = string.replace('
', '
').replace('
', '
')
    line_endings = self.view.settings().get('default_line_ending')
    if line_endings == 'windows':
        string = string.replace('
', '
')
    elif line_endings == 'mac':
        string = string.replace('
', '
')
    return string

The fix_whitespace() method is a little more complicated, but does the same kind of manipulation, just for the indentation and whitespace in the CSS block. This manipulation only really works with a single block of CSS, so we exit if one or more braces was included in the original selection.

def fix_whitespace(self, original, prefixed, sel, braces):
    # If braces are present we can do all of the whitespace magic
    if braces:
        return ('', prefixed, '')

Otherwise, we start by determining the indent level of the original CSS. This is done by searching for whitespace at the beginning of the selection.

(row, col) = self.view.rowcol(sel.begin())
indent_region = self.view.find('^s+', self.view.text_point(row, 0))
if self.view.rowcol(indent_region.begin())[0] == row:
    indent = self.view.substr(indent_region)
else:
    indent = ''

Next we trim the whitespace from the prefixed CSS and use the current view settings to indent the trimmed CSS to the original level using either tabs or spaces depending on the current editor settings.

prefixed = prefixed.strip()
prefixed = re.sub(re.compile('^s+', re.M), '', prefixed)

settings = self.view.settings()
use_spaces = settings.get('translate_tabs_to_spaces')
tab_size = int(settings.get('tab_size', 8))
indent_characters = '	'
if use_spaces:
    indent_characters = ' ' * tab_size
prefixed = prefixed.replace('
', '
' + indent + indent_characters)

We finish the method up by using the original beginning and trailing white space to ensure the new prefixed CSS fits exactly in place of the original.

match = re.search('^(s*)', original)
prefix = match.groups()[0]
match = re.search('(s*)Z', original)
suffix = match.groups()[0]

return (prefix, prefixed, suffix)

With the fix_whitespace() method we used the Python regular expression (re)module, so we need to add it to the list of imports at the top of the script.

import re

And with this, we’ve completed the process of writing the prefixr command.The next step it to make the command easy to run by providing a keyboard shortcut and a menu entry.


Step 10 - Key Bindings

Most of the settings and modifications that can be made to Sublime are done via JSON files, and this is true for key bindings. Key bindings are usually OS-specific, which means that three key bindings files will need to be created for your plugin. The files should be named Default (Windows).sublime-keymap, Default (Linux).sublime-keymap and Default (OSX).sublime-keymap.

Prefixr/
...
- Default (Linux).sublime-keymap
- Default (OSX).sublime-keymap
- Default (Windows).sublime-keymap
- Prefixr.py

The .sublime-keymap files contain a JSON array that contains JSON objects to specify the key bindings. The JSON objects must contain a keys and command key, and may also contain a args key if the command requires arguments. The hardest part about picking a key binding is to ensure the key binding is not already used. This can be done by going to the Preferences > Key Bindings – Default menu entry and searching for the keybinding you wish to use. Once you’ve found a suitably unused binding, add it to your .sublime-keymap files.

[
	{
		"keys": ["ctrl+alt+x"], "command": "prefixr"
	}
]

Normally the Linux and Windows key bindings are the same. The cmd key on OS Xis specified by the string super in the .sublime-keymap files. When porting a key binding across OSes, it is common for the ctrl key onWindows and Linux to be swapped out for super on OS X. This may not, however, always be the most natural hand movement, so if possible try and test your keybindings out on a real keyboard.


Step 11 - Menu Entries

One of the cooler things about extending Sublime is that it is possible to add items to the menu structure by creating .sublime-menu files. Menufiles must be named specific names to indicate what menu they affect:

  • Main.sublime-menu controls the main program menu
  • Side Bar.sublime-menu controls the right-click menu on a file or folder in the sidebar
  • Context.sublime-menu controls the right-click menu on a file being edited

There are a whole handful of other menu files that affect various other menus throughout the interface. Browsing through the Default package is the easiest way to learn about all of these.

For Prefixr we want to add a menu item to the Edit menu and some entries to the Preferences menu for settings. The following example is the JSON structure for the Edit menu entry. I’ve omitted the entries for the Preferences menu since they are fairly verbose being nested a few levels deep.

[
{
	"id": "edit",
	"children":
	[
	    {"id": "wrap"},
	    { "command": "prefixr" }
	]
}
]

The one piece to pay attention to is the id keys. By specifying the idof an existing menu entry, it is possible to append an entry without redefining the existing structure. If you open the Main.sublime-menu file from the Default package and browse around, you can determine what idyou want to add your entry to.

At this point your Prefixr package should look almost identical to the official version on GitHub.


Step 12 - Distributing Your Package

Now that you’ve taken the time to write a useful Sublime plugin, it is time to get into the hand of other users.

Sublime supports distributing a zip file of a package directory as a simple way to share packages. Simply zip your package folder and change the extension to .sublime-package. Other users may now place this into their Installed Packages directory and restart Sublime to install the package.

Along with easy availability to lots of users, having your package available via Package Control ensures users get upgraded automatically to your latest updates.

While this can certainly work, there is also a package manager forSublime called Package Controlthat supports a master list of packages and automatic upgrades. To get your package added to the default channel, simply host it on GitHubor BitBucket and then fork the channel file (on GitHub, or BitBucket), add your repository and send a pull request. Once the pull request is accepted, your package will be available to thousands of users using Sublime. Along with easy availability to lots of users, having your package available via Package Control ensures users get upgraded automatically to your latest updates.

If you don’t want to host on GitHub or BitBucket, there is a customJSON channel/repository system that can be used to host anywhere, while still providing the package to all users. It also provides advanced functionality like specifying the availability of packages by OS. See the PackageControl page for more details.


Go Write Some Plugins!

Now that we’ve covered the steps to write a Sublime plugin, it is time for you to dive in! The Sublime plugin community is creating and publishing new functionality almost every day. With each release, Sublime becomes more and more powerful and versatile. The Sublime Text Forum is a great place to get help and talk with others about what you are building.


November 12 2011

10:00

9 WordPress Security Tips To Protect Your Website From Harm

WordPress is the most popular Content Management System in the world, used by more than 60 million people around the globe. WordPress hosts more than half of the blogs itself. The popular CMS is used by huge companies and associations in the world such as TechCrunch, NBC, CNN, CBS or the National Football League of the US. There are more than 2.5 billion WordPress pages in the world, read by more than 300 million people daily, while around 500.000 new posts and 400.000 comments are posted each day.

This is huge and shows how important and widely used WordPress is. WordPress doesn’t show signs of slowing down either, so expect these numbers to increase dramatically in the near future. Therefore we also need to learn how to protect ourselves, because there is no popular web technology nowadays not targeted by hackers and robots.

Today I will talk about tips, tricks and plugins to keep your WordPress blog safe from hackers and robots. This doesn’t mean you have to do all of them, but using as many of them as possible is recommended.

1. Always Update

Keeping your WordPress updated all the time is important, because the developers work to solve security issues as well and if they release an update, it is a good idea to update. It takes only a few seconds, is safe (because WordPress backs up your data before actually updating, so you can’t lose anything) and will help your blog run better and be compatible with more plugins too. When you update, do it through your dashboard or if you want to do it manually, do not download the update from another site than WordPress.org.

2. Strengthen your password

Now this shouldn’t be something new to you. If you’ve been on the internet for some time you know strong passwords are recommended. Include small and capital letters, numbers and different symbols to make your password not difficult, but impossible to guess. Once somebody has full access to your blog, it’s not yours anymore!

3. Keep an eye on file permission

It is a good idea to keep an eye on the file permissions. You have a link at the end of the article with a guide about what file permissions are and how should they be used. You can set file permission with FTP clients and FileZilla works just fine, so I recommend it.

4. Use .htaccess

The .htaccess file is available by default in your hosting folder. You can use this file to block different IPs and you can learn how to do this by following the links at the bottom of the article.

5. Use SSL Encryption

SSL Encryption is used for encrypting data your blog sends. This means that nobody accessing your router can intercept the data you use, such as account credentials. This way your data is not only really difficult to intercept, but also to decrypt. The bad in general is that you have to pay for having an SSL encryption, but most of the services out there do a tremendous job and also help you set up the SSL server. However, for WordPress SSL encryption is free and you only have to add this particular line to your wp-config.php:

define (‘FORCE_SSL_ADMIN’, true);

6. Always Back-up

Backing up once a week is something I would like to recommend as well, because no matter how much you protect the blog, anything can happen. There are things you can’t even do anything about (like the host servers getting hijacked – which doesn’t really happen too often, but it is a possibility) and it is good to have a back-up which you can install again right away.

7. Protect the wp-config.php

This is one of the most important files in your WordPress folder, therefore you really have to protect it. You can hide it from public view by inserting few lines of code into your htaccess file:

<Files wp-config.php>

order allow, deny

deny from all

</Files>

This prevents the wp-config.php file from being seen by public users and makes it therefore more difficult to spot for hackers and robots.

8. Never use “admin” as login

A common mistake is to use “admin” as the login username. When you install WordPress, right after the process is done create a new account and use that one as default. The “admin” account is quite dangerous to use because all the robots go for it.

9. Use an SFTP

Most of the time people upload files by using FTP, but you could use a Secure FTP (SFTP) so that the files you send are encrypted. You can find a detailed guide about how to do this here.

Now we move onto plugins you can use to secure your WordPress.

1. Login Lockdown

You can use a plugin called Login Lockdown, but make sure you remember your password. Login Lockdown registers every failed login attempt and the IP of the person, and blocks the ability to login for a range of IPs if the number of failed logins exceeds the number you set. As a default setting, the plugin locks down IPs for an hour after 3 failed logins within 5 minutes. The IP addresses which have been blocked can be removed from the plugin panel in the WordPress dashboard.

Login Lockdown protects your WordPress login page from people trying to guess your password.

2. WP-DB-Backup

I told you earlier you should have backups for your database all the time. This is the plugin that I use for this purpose. It sends you backups on your e-mail or can also store them on the server. You can also set how often you wish the plugin to back up your data.

3. WP Security Scan

Removing the version of WordPress you have should be a basic option, but WordPress makes it difficult. Therefore you need to use a plugin to remove the version of WordPress from the header of your PHP page. Why? Because knowing which version you have means hackers know the security issues you have, therefore this makes it easier for them to hack you.

With all these plugins and tips being listed, I only wish to tell you that WordPress, although very popular and widely used, is threatened all the time by hackers and robots. WordPress security is something that has been discussed long and you should take a look into it, because finding out your blog is hacked and having no backup is definitely not fun. Try to avoid this by backing up regularly and following my tips and you will find yourself less often in troubles.

Further reading

You can read more about this topic on the following links:

Changing File Permissions on WordPress.org

Hardening WordPress on WordPress.org

Block IPs with .htaccess on htaccesstools

WordPress Security Tips and Hacks on Noupe

WordPress Security

11 Best Ways to Improve WordPress Security on ProBlogDesign

September 12 2011

10:00

Create Your Own Premium Membership WordPress Blog – Part 1/3

Who doesn’t want to earn money from blogging? I mean, sometimes you have shortages, sometimes comments let you down, payment is not THAT good. But you know, it’s still better than real work, right? (Troll’s comments in 3..2..1..)

So instead of spending a few bucks in order to get a premium membership system, why not create your own? And you can also learn a little bit about WordPress. Big deal, isn’t it? And you will be amazed at how easy is to build such great feature.

This is our first post from 3 and we’ll be talking about user roles, register, show / hide content based on user’s role.

So, Let’s Rock!

How will be our plugin

Our goal here is to get a plugin that allows us to publish premium content (with teasers for non-premium users) and normal content so we will get traffic anyway.

Basic functions:

  • Create a new user role – similar to subscriber but able to read premium content
  • Create users and add them to this role – sometimes WordPress default register form isn’t enough
  • Sidebar login / register – cool feature that may boost your conversion
  • Show / hide content based on user role – so premium will see almost everything :)
  • PayPal integration – Part 2
  • Create and control external db (Payment control)- Part 2
  • Manage cron jobs and wp-cron – Part 2
  • Different menus for logged in users – Part 2
  • Wp-Admin theming – Part 3

Create a new user role

First of all we need to know who is premium member and who isn’t. WordPress doesn’t have a “premium subscriber” role, but is pretty easy to create it.

If you’re not familiarized with basic plugin structure and planning, you should check out this basic tutorial that I’ve done a couple of months ago.

As you can see we have our basic plugin declaration and a simple snippet that create our brand new user role. To make sure this code is working just activate it (duh!) and go to Wp-admin -> users -> Add New and you should see this in your role select:

Did you notice that we’ve set our premium subscriber with ‘read’ and ‘read_premium’ capabilities? Yeah, we will use this read_premium capability to know if user can / cannot see some content. That’s good, but since we’ve just created this capability (right now!) any other user role (including admin) funnily won’t be able to get access to this premium content.

Now we will give them capability to do so:

This is really simple also, you just need be aware that once you give some capability for users (like this ‘read_premium’) they will have it, unless you remove. So if by mistake you add this capability to subscriber just removing the code won’t remove user capability. But this code will:

Ok, let me tell you a secret now, what we’ve done is actually really bad code. WordPress will run it every time it loads, but this snippet just have to run once (once created role and capability they remain intact until you delete them). So after debugging, let’s wrap all this code inside a register_activation_hook:


Create users and add them to this role

Ok, you have your role, but how to create users and add them to this role? Well, we will be talking about payment process later but you can prepare yourself to promote them to premium. Let’s create a function that promote our users (when you have payment, you run it):

But before promoting your users you have to create them, right? So we will prepare our system for doing that outside WordPress default register page, all you have to do is to call this function from anywhere (like from sidebar register, as we will see above):

Sidebar login /register

Let’s boost your conversion rate by creating a simple login / register sidebar form. This time we will need to make some changes in your theme, hope it’s ok with you.

We will need to make some changes in sidebar. Change it as you want, but basic code will be something like this:

So by the end of this point you will have:

  • If logged in, logout option and admin link if you’re admin
  • If not logged in, login and register form
  • Any error will show also

Ok, now we need to put functionality on it. We need to add this to our header.php (before DOCTYPE):

Then you will be able to register, login, and logout :)

Show / hide content based on user role

Now it’s what you were waiting for: how to show and hide stuff based on user role.

We will need a little setup at this point, go to wp-admin -> settings -> reading -> For each article in a feed, show = Summary. Do that so your feed will show only excerpts.

Then at this point we have 2 options, the lazy and the right way. The lazy one is just to add this code to your plugin:

Since this is the lazy option, as always in our lives, it will give more work :D Yeah you will need more setup and trust a lot in your theme developer to do that. But we have a better option, dear fried.

You can go trough your theme and search for crucial files like single.php, category.php, search.php, and why not home.php. Then when you think users can’t see premium content just put this:

This gives you more control, since you may want to give some free content categories ( just add them in your if).

So, what do you think?

As you can see, this is just our start point, dear Padawan. We will dive a little bit more on that later, but hope you’ve had enough fun for now :)

July 05 2011

10:00

WordPress Plugin Development – Relate Posts as a Series Part 2

So, we started our dive into WordPress plugin development with the first part of this tutorial where we talked a little about planning, basic plugin structure, custom post types, metaboxes and how to add custom functions to WordPress’s defaults actions.

Today we will talk a little more about metaboxes and jQuery, shortcodes, and front-end functionality.

All these things with a pretty practical example of how to make a plugin that will relate posts as a series.

So, let’s rock!

A little recap… and download!

Last time we completed the first three steps:

  1. Planning – We’ve made our entity-relationship diagram to know which data we would have to store
  2. Create our plugin and custom post type – We’ve created the basic file for our plugin, and registered our series custom post type
  3. Post functionality – We’ve made some metaboxes to store custom data, and added them to WordPress’s default post saving function via actions.

If you didn’t read the first part of this tutorial, I highly recommend you to do this now, but if you don’t want to, you can still understand the functions and logic we are using here and make use of it.

Well, for people who are in a hurry, you can download the fully working plugin and make use of it without having to copy/paste all this code ;).

Step 4 – Series functionality

Registering our metabox

After we have control over all our posts related to series, we need to be able to manually edit the series itself.

In order to do this, we will need some metaboxes on them also. So, let’s edit our plugin with this code (here is just the additional code to avoid any confusion with the code that I explained last time, and won’t explain now):

<?php<br /-->//this function will register our metabox for wd_series custom post type
	function wd_call_meta() {
		add_meta_box(
			'series-data', // id of the <div> we'll add
			'Series Custom Data', //title
			'wd_series_options', // callback function that will echo the box content
			'wd_series', // where to add the box: on "post", "page", or "link" page
			'side', //positioning
			'low' //positioning
		);
	}
//with this we call it!
add_action('admin_menu', 'wd_call_meta');
?>

Our HTML metabox and jQuery enhancements

So, as you can see this function doesn’t have the metabox itself, it just says “Hey, WordPress, you should add function wd_series_options as a metabox for this guy!”. So we now need the metabox itself.

This is a tricky part since this box will give the user the ability to add “fake” posts to the series, so our readers could be interested in this series content. So what do we have now is:

  • Standard posts for a series, added via post editing screen
  • Fake posts for a series, added via series editing screen
  • Delete option, to remove a post from a series

We have also the opening / closing option for a series, and a really important attribute, the size of the series, so we don’t get lost in all our counters.

To get this working we will need some jQuery. We will have a “model” row, and when the user wants to add more lines we will get this model and duplicate it inside our form. We have to pay attention in regards to recovering data. We have to dynamically add rows as they are needed by one series. And we have, of course, some CSS for that.

Let’s do it this way:

<?php

function wd_series_options() {
		global $post;
		//get saved data
		$custom    = get_post_custom($post->ID);
		$open      = $custom["open"][0];
		$numFields = $custom["size"][0];

		$openNo = $openYes = "";
		if ($open == "yes") {
			$openYes = "checked = 'checked'";
		} else {
			$openNo = "checked = 'checked'";
		}

		$series_items = array();
		$i = 0;
		while($i < $numFields) {
			$i++;
			$key = "name_".$i;
			$series_items[$i] = $custom[$key][0];
		}
		$numFields++;
?>

<table>
<tbody>
<tr class="space">
<td><label>Open?</label></td>
<td>
				<label><input id="wd_open" name="wd_open" type="radio" value="yes" /> /> Yes, it is open.</label>

				<label><input id="wd_open" name="wd_open" type="radio" value="no" /> /> No, it is closed</label></td>
</tr>
</tbody>
</table>
	<table class="default-line">
		<tr>
			<td><input id="order_K" name="order_K" type="text" value="" size="5" /></td>
			<td><input id="name_K" name="name_K" type="text" value="" /></td>
			<td class="check"><input id="remove_K" name="remove_K" type="checkbox" value="remove" /></td>
		</tr>
	</table>
	<input type="hidden" id="NumFields" name="NumFields" value="<?php echo $numFields; ?>" />
	<table>
		<tr>
			<td>Order</td>
			<td>PostName</td>
			<td class="checkboxTd">Remove?</td>
		</tr>
	</table>
	<div class="ins">
	<?php
		foreach($series_items as $key => $name) {
			echo "<table>";
				echo "<tr>";
					echo "<td><input id='order_$key' name='order_$key' type='text' value='$key' size='5' /></td>";
					echo "<td><input id='name_$key' name='name_$key' type='text' value='$name' /></td>";
					echo "<td class='check'><input id='remove_$key' name='remove_$key' type='checkbox' value='remove' /></td>";
				echo "</tr>";
			echo "</table>";
		}
	?>
	</div>
	<table>
		<tr id="addItem">
<td colspan="3"><a id="clickLink" class="link" onclick="addLine();">Add new line</a></td>
</tr>
</tbody>
</table>
<style type="text/css">
	.default-line {
		display: none;
	}
	#series-data table {
		width: 100%
	}
		#series-data tr.space td {
			padding-bottom: 10px;
		}
			#series-data .space label {
				padding-right: 20px
			}
		#series-data .check {
			text-align: center;
		}
		#addItem td {
			padding-top: 10px;
			text-align: right;
		}
	.checkboxTd {
		width: 20px;
	}
	.link { cursor: pointer; }
</style>
<script type="text/javascript">
	function addLine() {
		jQuery(".default-line").clone().appendTo(".ins");
		var numElem = jQuery("#NumFields").attr('value');
		jQuery(".ins .default-line").fadeIn().removeClass('default-line');
		correctsLine(numElem);
	}
	function correctsLine(nID) {
		//goes switching K to correct number of line
		fieldName  = "order_" + nID;
		jQuery(".ins input#order_K").attr('value', ( parseInt(nID)+1) ).attr('id', fieldName).attr('name', fieldName);

		fieldName  = "name_" + nID;
		jQuery(".ins input#name_K").attr('id', fieldName).attr('name', fieldName);

		fieldName  = "remove_" + nID;
		jQuery(".ins input#remove_K").attr('id', fieldName).attr('name', fieldName);

		//corrects number of fields
		nID++;
		jQuery("#NumFields").attr('value', nID);
	}
	jQuery(window).load(function(){
		addLine(); //adds first (blank) row
	});
</script>

With this code you should see something like this as your series metabox:

Edit our default post saving function

And when you click on “Add new line”, believe me, it should create a fresh and brilliant new line.

Now we have this pretty box, but when you click “Update” nothing happens. This is why we haven’t prepared our WordPress insert post function to treat this data. What we have to do now it to say to WordPress “Hey, when you see this field in wd_series post type, delete all old data and save this new one for me, ok?”.

One important thing to note here is that we must delete all previous data and use some logic to reorder the series when needed.

Our magic here relies on ksort php function, so we save a temporary array and save all the items in the correct order after run this function.

Well, let’s do it:

<?php //we need a function that recieves post_id and $_POST data
function wd_meta($post_id, $post = null) {
//gets our POST custom data and saves it as meta keys, when needed
/* we have to save this metafields: open = Yes / No for open / closed series
size = how many items do we have in this series, so we can adjust our order counter
name_ORDER = the name of the ORDER'th item
post_ORDER = ID of the ORDER'th item
order_POST = Order of the ID (post) */
if( $post->post_type == "wd_series"  ) {
			//update series state (open / closed)
			$open = @$_POST["wd_open"];
			update_post_meta( $post_id, "open", $open );

			$size = @$_POST["NumFields"];
			$i = 0;

			$organize = array();
			while ($i < $size) {
				//let's pre-organize all posts
				$survive = $key = $remove = $order = $name = $post = null;

				$key = "remove_".$i;
				$remove = @$_POST[$key];

				if (empty($remove)) {
					//we won't delete this guy, and we'll put he in his right order
					$key = "order_".$i;
					$order = @$_POST[$key];

					$key = "name_".$i;
					$name = @$_POST[$key];

					$key = "post_".$i;
					$post = get_post_meta($post_id, $key, true);

					if (!empty($name)) {
						$organize[$order] = array( 'name' => $name, 'post' => $post);
						$survive = true;
					}
				}
				//we will pre delete everybody, to prevent trash in here
				$key = "name_".$i;
				delete_post_meta($post_id, $key);

				$key = "post_".$i;
				$post = get_post_meta($post_id, $key, true);
				delete_post_meta($post_id, $key);

				$key = "order_".$post;
				delete_post_meta($post_id, $key);

				//if it won't survive, we delete series_id from post_id
				if(!$survive) {
					$key = "series_id";
					delete_post_meta($post, $key);
				}
				$i++;
			}
			//let's correctly order this
			ksort($organize);
			$i = 0;
			foreach($organize as $item) {
				$i++;

				$key = "name";
				$nam = $item[$key];
				$key = "name_".$i;
				update_post_meta( $post_id, $key, $nam );

				$key  = "post";
				$post = $item[$key];
				if(!empty($post)) {
					$key = "post_".$i;
					update_post_meta( $post_id, $key, $post );
					$key = "order_".$post;
					update_post_meta( $post_id, $key, $i );
				}
			}

			$size = count($organize);
			update_post_meta( $post_id, "size", $size );
		}
	}
	//it's me saying to wordpress "Hey guy, don't forget to save this data when you insert or update posts!"
	add_action("wp_insert_post", 'wd_meta', 10, 2);
?>

Now we have our plugin working, let’s improve it.

Step 5 – Shortcodes and theming functions

Before we can output our posts we have to prepare two kind functions:

  • Common theming functions – Something like wd_series($args), so we can use for theming and widgets
  • Shortcodes – Something like [wd-series] so we can insert it directly from content edit mode.

Common functions

We will need to run a get_post loop, because probably our series will be shown inside another WordPress loop, so we can’t use WordPress’ default loop. Think about it this way: we will show a series when we are INSIDE a post, right? Thus the best way is via get_post.

Then we will just prepare a simple output function based on current post’s ID so it will show all items for the series related to it.

As we store the series related to this post inside “series_id” custom field, we just need to run a get_post for this series_id and output all metadata about series items.

Since for every item the output function is potentially the same, we will create two functions this time, one for items output and other for complete series output, as follow:

<?php //display item with or without link
function wd_item( $name, $postItem ) {
	if ( ! empty ( $postItem ) ) {
		$link = get_permalink($postItem);
		echo "<a title="$name" href="$link">$name</a>";
	} else {
		echo $name;
	}
}
//output!
function wd_series ($series) {
	$title = get_the_title($series);
	$meta  = get_post_custom($series);

	echo "<h3>$title</h3>";
	$size = $meta["size"][0];
	$i = 1;
	echo "<ol>";
	while ($i <= $size) {
		$key = "name_".$i;
		$name = $meta[$key][0];

		$key = "post_".$i;
		$post_item = $meta[$key][0];

		echo "<li>";
			wd_item( $name, $post_item);
		echo "</li>";

		$i++;

		$name = $post_item = null;
	}
	echo "</ol>";
}
?>

Shortcodes

So with the function above we can output our series in our template, and it is pretty customizable as you can see. But what if you want to give your writers the ability to decide where the series content should appear? Well, to do this you will need a shortcode.

Long story short, they give the ability to call functions via post content. So while I’m writing this post I could write [wd-series] and BAM! our series content would have to appear just above this text.

It is pretty easy to register a shortcode, and as long as we have our output function defined it will be even easier. With no more than six lines you can do it:

<?php // [wd-series]
function wd_series_shortcode() {
              global $post;
              $series = get_post_meta($post--->ID, "series_id", true);

              wd_series($series);
}
add_shortcode( 'wd-series', 'wd_series_shortcode' );
?>

After all this code, you will see something similar to this when you write [wd-series] in your content box:

Are you hungry yet?

This code surely could be improved and I know that some of our brilliant readers could point out some things to make it better. So why not leave a comment and share your thoughts?

And finally, I recommend you dig a little deeper into the  Shortcodes API, since it is a great tool when well used!

June 06 2011

10:00

jQuery Plugin: Table of Contents with Smooth Scrolling

Hey guys, have you noticed that pretty box on WordPress codex that gives us a preview about what we can see on a page? So, I haven’t seen too many blogs use this kind of feature and it is really useful for our readers, since they can just skip to the content that they are interested in and avoid wasting time. Wikipedia has a table of contents that makes it easier for readers to skip around, right?

I’m not the very first to do something like this with jQuery. But our goal in here is to develop a complete jQuery plugin, from start to finish, with options, and that is easy to customize. And, of course, something that I hope is useful to you

So, let’s rock!

STOC – Smooth Table of Contents jQuery plugin

Since there are a lot of “tocs” around the web, our plugin will be called STOC and the main features are:

  • Automatically adds the table of contents to target element
  • You can select to search just a part of you page
  • You can select what is the first heading we will have to search (h1, h2…)
  • You can select the “depth” of the search
  • SubItems are made of sublists inside parent item
  • You can select which text will display before the table (title)
  • You can select whether ol or ul to you listing
  • You can enable / disable smooth scrolling

Here is how it should look in our demo:

Here’s a running Demo. You can also download all files here.

Planning and planning – Before code, let’s think about it

The main idea is to have a jQuery plugin that generates a table of content inside the target element. To have this working we need some basic customization with these options:

  • Where to search – If the table is generated based on entire page, just a section content
  • Depth of H’s – How many “levels” of titles we will have in our search
  • Start tag – Which level of heading will be the first on set (h1, h2, h3)
  • Title if the box – What to display as box’s title
  • List type – whether to have ordered or unordered list

The hardest thing when we are doing something just for fun is to define the scope. Actually it is hard too when we have a “real” project, but when it comes to pet projects it is harder because you just can’t measure accurately what will bring you the expected revenue (fun).

So, what do I do in these cases is list anything that I could do on it, and just cut down what will take too much time and will not be so good to do.

In this case, for example I listed these features:

  • Customizable via options – I think this one was essential, so I just kept it
  • Smooth scrolling - This one I didn’t see in any other plugin / snippet. It would be good to have, so I kept it.
  • Accordion for hierarchy - I found this idea really cool, but useless, I drop it.
  • Preview of the text on hover - I’ve stolen this idea of one site but actually didn’t find it useful also, so I drop it.

So what I’ve done here is to define which of the cool features had big potential to be a waste of time. Even if I had more time to code I would never use them, just because they haven’t the expected benefit (fun x time).

Now that we now what we want to do, let’s start to code.

Basic plugin structure with options

First we need to create our file. The standard for jQuery plugins files names is jQuery.PLUGINNAME.js so, our file will be jquery.stoc.js.

We also have all our options defined above, so we need now to save a variable for each one of them, so our user can send his own parameters.

Here is our commented code:

/*
This line creates our function "wrapped" by jQuery container, so we won't have any problem with others libraries
*/
(function($){
/*
Here the standard is $.fn.PLUGINNAME. so when we call $(element).stoc() jquery will run this code
Pay attention that we pass options to our funcion, so when user defines it we can extend our plugin
*/
	$.fn.stoc = function(options) {
	//Our default options
	var defaults = {
		search: "body", //where we will search for titles
		depth: 6, //how many hN should we search
		start: 1, //which hN will be the first (and after it we go just deeper)
		stocTitle: "<h2>Contents</h2>", //what to display before our box
		listType: "ul", //could be ul or ol
		smoothScroll: 1
	};

	//let's extend our plugin with default or user options when defined
	var options = $.extend(defaults, options);

	return this.each(function() {
		//our functions here
		alert("I'm a beta tester alert box!");
	});
};
})(jQuery);

Let’s try a simple demo to see it working. Create this HTML in same folder as our plugin:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Smooth Table Of Contents jQuery plugin - DEMO</title>
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
	<script type="text/javascript" src="jquery.stoc.js"></script>
	<script type="text/javascript">
		$(function(){
			$("#items").stoc();
		});
	</script>
	<style type="text/css">
		body {
			background: #fafafa url(handmadepaper.png); //via subtlepatterns
		}
			#container {
				position: relative;
				top: 50px;
				width: 960px;
				margin: 0 auto;
				padding-bottom: 20px;
			}
			#container p, #container h1, #container h2, #container h3, #container h4, #container h5 {
				font-family: "arial";
				padding: 10px 20px 0;
				margin: 0
			}
			#items {
				float: right;
				width: 260px;
				padding-bottom: 10px;
				margin:0 0 10px 20px;
				/* rgba with ie compatibility */
				background-color: transparent;
				background-color: rgba(255,255,255,0.4);
				filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#20ffffff,endColorstr=#20ffffff);
				-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#20ffffff,endColorstr=#20ffffff)";
			}
				#items ul {
					margin: 0 0 0 20px;
					padding: 0 0 5px;
					list-style-type: none;
				}
					#items ul ul {
						font-size: 90%;
					}
				#items ul a {
					font-family: "arial";
					text-decoration: none;
					color: #c10000;
				}
					#items ul a:hover { color: #ff0000 }
	</style>
</head>
<body id="page-1">
	<div id="container">
		<div id="items">
		</div>
		<h1>1 - Phasellus vulputate</h1>
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas metus est, egestas vel aliquet at, pellentesque nec lorem. Pellentesque molestie bibendum eros, eu suscipit nisi volutpat fringilla. Vivamus fringilla nisl ut ante commodo porta. Morbi ipsum nunc, sollicitudin ac pretium pretium, iaculis vel enim. Nulla cursus porta orci, sed vulputate magna feugiat et. Aliquam nibh massa, pharetra tincidunt vehicula ac, pellentesque vitae nibh. In lobortis semper eros fermentum pretium. Sed posuere, urna eget ornare luctus, mi lectus lacinia leo, sit amet faucibus orci ipsum sit amet ipsum. Maecenas sapien neque, ultrices a lacinia sit amet, fermentum non enim. Integer at venenatis orci. In hac habitasse platea dictumst.</p>
		[... lot of more lipsum text with h's here]
	</div>
</body>
</html>

If you create this file, when you load it you should see our pretty beta tester alert. So our plugin is being called (make sure that you add jquery before it, as I’ve done including api.googleapis…). if you want to overwrite any option defined before, you just have to pass it as .stoc({ OPTIONNAME: VALUE }) instead of just .stoc(). For example, to define our search just in #container, add .stoc({ search: "#container" }).

How should we select our headings?

Now we have to prepare our plugin to get all h’s that we have to (based in our options). What we can do is get all the headings we have to, and when we loop through each one of them we will discover which level it is. I think it is easier than trying to get the whole hierarchy for each “tree” of headings.

Since our current object can change as we run our code, we have also to “cache” our current object so we will always now which object we are modifying. Our code now will be:

   return this.each(function() {
		//"cache" our target and search objects
		obj = $(this); //target
		src = $(options.search); //search
		//let's declare some variables. We need this var declaration to create them as local variables (not global)
		var appHTML = "", tagNumber = 0, txt = "", id = "", before = "", after = "", previous = options.start, start = options.start, depth = options.depth, i = 0, srcTags = "h" + options.start, cacheHN = "";

		//which tags we will search
		while ( depth > 1) {
			start++; //we will just get our start level and numbers higher than it
			srcTags = srcTags + ", h" + start;
			depth--; //since went one level up, our depth will go one level down
		}

    });

If you alert you srcTags you will see something like this “h1, h2, h3, h4, h5, h6″. This is what we will pass to jQuery as the elements that we want to search for.

Building our table

We have all our elements, what we have to do is run a function on each one of them with the wonderful each() jQuery function.

Inside each element, we need to:

  • Know which level the current element is (tagNumber)
  • Set one id to this element, if it doesn’t have one
  • Get the elements text
  • Test if is its level is lower, higher or equal than previous element and open / close ul’s based on this
    • If element number is higher than previous means that we went down one level (e.g. from h2 to h3)
    • If element number is equals to previous means that we stay on same level (e.g. h4)
    • If element number is lower than previous means that we went up, but we don’t know how many levels (e.g. from h4 to h1)
  • Append element HTML to our target item

We also have to correct the last item because if it is not top-level it will let some uls open, and we don’t want it :D

Our commented code now will be:

/* our setup stuff here */
/*inside our return function */
	//which tags we will search
		while ( depth > 1) {
			start++; //we will just get our start level and numbers higher than it
			srcTags = srcTags + ", h" + start;
			depth--; //since went one level up, our depth will go one level down
		}
		src.find(srcTags).each(function() {
			//we will cache our current H element
			cacheHN = $(this);
			//if we are on h1, 2, 3...
			tagNumber = ( cacheHN.get(0).tagName ).substr(1);

			//sets the needed id to the element
			id = cacheHN.attr('id');
			if (id == "") { //if it doesn't have only, of course
				id = "h" + tagNumber + "_" + i;
				cacheHN.attr('id', id);
			}
			//our current text
			txt = cacheHN.text();

			switch(true) { //with switch(true) we can do comparisons in each case
				case (tagNumber > previous) : //it means that we went down one level (e.g. from h2 to h3)
						appHTML = appHTML + "<" + options.listType +"><li>"+ before +"<a href=\"#"+ id + "\">" + txt + "</a>";
						previous = tagNumber;
					break;
				case (tagNumber == previous) : //it means that stay on the same level (e.g. h3 and stay on it)
						appHTML = appHTML + "</li><li>"+ before +"<a href=\"#"+ id + "\">" + txt +  "</a>";
					break;
				case (tagNumber < previous) : //it means that we went up but we don't know how much levels  (e.g. from h3 to h2)
						while(tagNumber != previous) {
							appHTML = appHTML + "</" + options.listType +"></li>";
							previous--;
						}
						appHTML = appHTML + "<li>"+ before +"<a href=\"#"+ id + "\">" + txt + "</a></li>";
					break;
			}
			i++;
		});
		//corrects our last item, because it may have some opened ul's
		while(tagNumber != options.start) {
			appHTML = appHTML + "</" + options.listType +">";
			tagNumber--;
		}
		//append our html to our object
		appHTML = options.stocTitle + "<"+ options.listType + ">" + appHTML + "</" + options.listType + ">";
		obj.append(appHTML);

How to Make our STOC smoother

I’ve stolen CSS trick’s smooth scroll code, but I hope they don’t mind :D

What we have to do here is just put this (compressed) function to load when our smooth scroll in on (if the user doesn’t set it as 0).

/*all code above in here*/
	//append our html to our object
		appHTML = options.stocTitle + "<"+ options.listType + ">" + appHTML + "</" + options.listType + ">";
		obj.append(appHTML);

		//our pretty smooth scrolling here
		// acctually I've just compressed the code so you guys will think that I'm the man . Source: http://css-tricks.com/snippets/jquery/smooth-scrolling/
		if (options.smoothScroll == 1) {
			$(window).load(function(){
				function filterPath(string){return string.replace(/^\//,'').replace(/(index|default).[a-zA-Z]{3,4}$/,'').replace(/\/$/,'')}var locationPath=filterPath(location.pathname);var scrollElem=scrollableElement('html','body');obj.find('a[href*=#]').each(function(){var thisPath=filterPath(this.pathname)||locationPath;if(locationPath==thisPath&&(location.hostname==this.hostname||!this.hostname)&&this.hash.replace(/#/,'')){var $target=$(this.hash),target=this.hash;if(target){var targetOffset=$target.offset().top;$(this).click(function(event){event.preventDefault();$(scrollElem).animate({scrollTop:targetOffset},400,function(){location.hash=target})})}}});function scrollableElement(els){for(var i=0,argLength=arguments.length;i<argLength;i++){var el=arguments[i],$scrollElement=$(el);if($scrollElement.scrollTop()>0){return el}else{$scrollElement.scrollTop(1);var isScrollable=$scrollElement.scrollTop()>0;$scrollElement.scrollTop(0);if(isScrollable){return el}}}return[]}
			});
		}

Our final result is this:

(function($){
 $.fn.stoc = function(options) {
	//Our default options
	var defaults = {
		search: "body", //where we will search for titles
		depth: 6, //how many hN should we search
		start: 1, //which hN will be the first (and after it we go just deeper)
		stocTitle: "<h2>Contents</h2>", //what to display before our box
		listType: "ul", //could be ul or ol
		smoothScroll: 1
	};

	//let's extend our plugin with default or user options when defined
	var options = $.extend(defaults, options);

    return this.each(function() {
		//"cache" our target and search objects
		obj = $(this); //target
		src = $(options.search); //search
		//let's declare some variables. We need this var declaration to create them as local variables (not global)
		var appHTML = "", tagNumber = 0, txt = "", id = "", before = "", after = "", previous = options.start, start = options.start, depth = options.depth, i = 0, srcTags = "h" + options.start, cacheHN = "";

		//which tags we will search
		while ( depth > 1) {
			start++; //we will just get our start level and numbers higher than it
			srcTags = srcTags + ", h" + start;
			depth--; //since went one level up, our depth will go one level down
		}
		src.find(srcTags).each(function() {
			//we will cache our current H element
			cacheHN = $(this);
			//if we are on h1, 2, 3...
			tagNumber = ( cacheHN.get(0).tagName ).substr(1);

			//sets the needed id to the element
			id = cacheHN.attr('id');
			if (id == "") { //if it doesn't have only, of course
				id = "h" + tagNumber + "_" + i;
				cacheHN.attr('id', id);
			}
			//our current text
			txt = cacheHN.text();

			switch(true) { //with switch(true) we can do comparisons in each case
				case (tagNumber > previous) : //it means that we went down one level (e.g. from h2 to h3)
						appHTML = appHTML + "<" + options.listType +"><li>"+ before +"<a href=\"#"+ id + "\">" + txt + "</a>";
						previous = tagNumber;
					break;
				case (tagNumber == previous) : //it means that stay on the same level (e.g. h3 and stay on it)
						appHTML = appHTML + "</li><li>"+ before +"<a href=\"#"+ id + "\">" + txt +  "</a>";
					break;
				case (tagNumber < previous) : //it means that we went up but we don't know how much levels  (e.g. from h3 to h2)
						while(tagNumber != previous) {
							appHTML = appHTML + "</" + options.listType +"></li>";
							previous--;
						}
						appHTML = appHTML + "<li>"+ before +"<a href=\"#"+ id + "\">" + txt + "</a></li>";
					break;
			}
			i++;
		});
		//corrects our last item, because it may have some opened ul's
		while(tagNumber != options.start) {
			appHTML = appHTML + "</" + options.listType +">";
			tagNumber--;
		}
		//append our html to our object
		appHTML = options.stocTitle + "<"+ options.listType + ">" + appHTML + "</" + options.listType + ">";
		obj.append(appHTML);

		//our pretty smooth scrolling here
		// acctually I've just compressed the code so you guys will think that I'm the man . Source: http://css-tricks.com/snippets/jquery/smooth-scrolling/
		if (options.smoothScroll == 1) {
			$(window).load(function(){
				function filterPath(string){return string.replace(/^\//,'').replace(/(index|default).[a-zA-Z]{3,4}$/,'').replace(/\/$/,'')}var locationPath=filterPath(location.pathname);var scrollElem=scrollableElement('html','body');obj.find('a[href*=#]').each(function(){var thisPath=filterPath(this.pathname)||locationPath;if(locationPath==thisPath&&(location.hostname==this.hostname||!this.hostname)&&this.hash.replace(/#/,'')){var $target=$(this.hash),target=this.hash;if(target){var targetOffset=$target.offset().top;$(this).click(function(event){event.preventDefault();$(scrollElem).animate({scrollTop:targetOffset},400,function(){location.hash=target})})}}});function scrollableElement(els){for(var i=0,argLength=arguments.length;i<argLength;i++){var el=arguments[i],$scrollElement=$(el);if($scrollElement.scrollTop()>0){return el}else{$scrollElement.scrollTop(1);var isScrollable=$scrollElement.scrollTop()>0;$scrollElement.scrollTop(0);if(isScrollable){return el}}}return[]}
			});
		}
    });
 };
})(jQuery);

Are you hungry yet?

What about you help me with some improvements on this plugin? Do you have any tip? Anything that you can think of a better way to do?

Do you have any other features in mind? Or even another plugin idea that you’d like to see a tutorial on?

Share your thoughts with us! :D

May 04 2011

21:59

Must-Have (Free) Photoshop Plugin: GuideGuide [CS4, CS5]

I’ve recently come across a lifesaver Photoshop plugin that is gonna rock your world. It’s called GuideGuide from Cameron McEfee and it’s a godesend for creating print layouts, and web for that matter. GuideGuide is free, and its a “panel” that assists you with laying out your guides across the artboard/document. Instead of having to do the math with complicated layouts, you can simply tell guide guide how far from each side of the document you want to place a guide. So simple it hurts.

GuideGuide can even find the center of a selection! You can set the number of columns, and gutter width as well. This is one USEFUL plugin, and I wanted to share it with everyone. Thanks to my friend Mike for the tip. :)

Must-Have (Free) Photoshop Plugin: GuideGuide [CS4, CS5]

March 08 2011

13:52

Ten Things Every WordPress Plugin Developer Should Know

Advertisement in Ten Things Every WordPress Plugin Developer Should Know
 in Ten Things Every WordPress Plugin Developer Should Know  in Ten Things Every WordPress Plugin Developer Should Know  in Ten Things Every WordPress Plugin Developer Should Know

Plugins are a major part of why WordPress powers millions of blogs and websites around the world. The ability to extend WordPress to meet just about any need is a powerful motivator for choosing WordPress over other alternatives. Having written several plugins myself, I’ve come to learn many (but certainly not all) of the ins-and-outs of WordPress plugin development, and this article is a culmination of the things I think every WordPress plugin developer should know. Oh, and keep in mind everything you see here is compatible with WordPress 3.0+.

Don’t Develop Without Debugging

The first thing you should do when developing a WordPress plugin is to enable debugging, and I suggest leaving it on the entire time you’re writing plugin code. When things go wrong, WordPress raises warnings and error messages, but if you can’t see them then they might as well have not been raised at all.

Wordpress Plugins Screenshot in Ten Things Every WordPress Plugin Developer Should Know

Enabling debugging also turns on WordPress notices, which is important because that’s how you’ll know if you’re using any deprecated functions. Deprecated functions may be removed from future versions of WordPress, and just about every WordPress release contains functions slated to die at a later date. If you see that you are using a deprecated function, it’s best to find its replacement and use that instead.

How to Enable Debugging

By default, WordPress debugging is turned off, so to enable it, open wp-config.php (tip: make a backup copy of this file that you can revert to later if needed) in the root of your WordPress installation and look for this line:

define('WP_DEBUG', false);

Replace that line with the following:

// Turns WordPress debugging on
define('WP_DEBUG', true);

// Tells WordPress to log everything to the /wp-content/debug.log file
define('WP_DEBUG_LOG', true);

// Doesn't force the PHP 'display_errors' variable to be on
define('WP_DEBUG_DISPLAY', false);

// Hides errors from being displayed on-screen
@ini_set('display_errors', 0);

With those lines added to your wp-config.php file, debugging is fully enabled. Here’s an example of a notice that got logged to /wp-content/debug.log for using a deprecated function:

[15-Feb-2011 20:09:14] PHP Notice: get_usermeta is deprecated since version 3.0! Use get_user_meta() instead. in C:\Code\Plugins\wordpress\wp-includes\functions.php on line 3237

With debugging enabled, keep a close eye on /wp-content/debug.log as you develop your plugin. Doing so will save you, your users, and other plugin developers a lot of headaches.

How to Log Your Own Debug Statements

So what about logging your own debug statements? Well, the simplest way is to use echo and see the message on the page. It’s the quick-and-dirty-hack way to debug, but everyone has done it one time or another. A better way would be to create a function that does this for you, and then you can see all of your own debug statements in the debug.log file with everything else.

Here’s a function you can use; notice that it only logs the message if WP_DEBUG is enabled:

function log_me($message) {
    if (WP_DEBUG === true) {
        if (is_array($message) || is_object($message)) {
            error_log(print_r($message, true));
        } else {
            error_log($message);
        }
    }
}

And then you can call the log_me function like this:

log_me(array('This is a message' => 'for debugging purposes'));
log_me('This is a message for debugging purposes');

Use the BlackBox Debug Bar Plugin

I only recently discovered this plugin, but it’s already been a huge help as I work on my own plugins. The BlackBox plugin adds a thin black bar to the top of any WordPress post or page, and provides quick access to errors, global variables, profile data, and SQL queries.

Debug-bar-black1 in Ten Things Every WordPress Plugin Developer Should Know

Clicking on the Globals tab in the bar shows all of the global variables and their values that were part of the request, essentially everything in the $_GET, $_POST, $_COOKIE, $_SESSION, and $_SERVER variables:

Debug-bar-globals1 in Ten Things Every WordPress Plugin Developer Should Know

The next tab is the Profiler, which displays the time that passed since the profiler was started and the total memory WordPress was using when the checkpoint was reached:

Debug-bar-profiler1 in Ten Things Every WordPress Plugin Developer Should Know

You can add your own checkpoints to the Profiler by putting this line of code anywhere in your plugin where you want to capture a measurement:

apply_filters('debug', 'This is a checkpoint');

Perhaps the most valuable tab in the BlackBox plugin is the SQL tab, which shows you all of the database queries that executed as part of the request. Very useful for determining long-running database calls:

Debug-bar-sql1 in Ten Things Every WordPress Plugin Developer Should Know

And finally we have the Errors tab, which lists all of the notices, warnings, and errors that occurred during the request:

Debug-bar-errors1 in Ten Things Every WordPress Plugin Developer Should Know

By providing quick access to essential debug information, the BlackBox plugin is a big-timer when it comes to debugging your WordPress plugin.

Prefix Your Functions

One of the first things that bit me when I started developing WordPress plugins was finding out that other plugin developers sometimes use the same names for functions that I use. For example, function names like copy_file(), save_data(), and database_table_exists() have a decent chance of being used by other plugins in addition to yours.

The reason for this is because when WordPress activates a plugin, PHP loads the functions from the plugin into the WordPress execution space, where all functions from all plugins live together. There is no separation or isolation of functions for each plugin, which means that each function must be uniquely named.

Fortunately, there is an easy way around this, and it’s to name all of your plugin functions with a prefix. For example, the common functions I mentioned previously might now look like this:

function myplugin_copy_file() {
}

function myplugin_save_data() {
}

function myplugin_database_table_exists() {
}

Another common naming convention is to use a prefix that is an abbreviation of your plugin’s name, such as “My Awesome WordPress Plugin”, in which case the function names would be:

function mawp_copy_file() {
}

function mawp_save_data() {
}

function mawp_database_table_exists() {
}

There is one caveat to this, however. If you use PHP classes that contain your functions (which in many cases is a good idea), you don’t really have to worry about clashing with functions defined elsewhere. For example, let’s say you have a class in your plugin named “CommonFunctions” with a copy_file() function, and another plugin has the same copy_file() function defined, but not in a class. Invoking the two functions would look similar to this:

// Calls the copy_file() function from your class
$common = new CommonFunctions();
$common->copy_file();

// Calls the copy_file() function from the other plugin
copy_file();

By using classes, the need to explicitly prefix your functions goes away. Just keep in mind that WordPress will raise an error if you use a function name that’s already taken, so keep an eye on the debug.log file to know if you’re in the clear or not.

Global Paths Are Handy

Writing the PHP code to make your plugin work is one thing, but if you want to make it look and feel good at the same time, you’ll need to include some images, CSS, and perhaps a little JavaScript as well (maybe in the form of a jQuery plugin). And in typical fashion, you’ll most likely organize these files into their own folders, such as “images”, “css”, and “js”.

That’s all well and good, but how should you code your plugin so that it can always find those files, no matter what domain the plugin is running under? The best way that I’ve found is to create your own global paths that can be used anywhere in your plugin code.

For example, I always create four global variables for my plugins, one each for the following:

  • The path to the theme directory
  • The name of the plugin
  • The path to the plugin directory
  • The url of the plugin

For which the code looks like this:

if (!defined('MYPLUGIN_THEME_DIR'))
    define('MYPLUGIN_THEME_DIR', ABSPATH . 'wp-content/themes/' . get_template());

if (!defined('MYPLUGIN_PLUGIN_NAME'))
    define('MYPLUGIN_PLUGIN_NAME', trim(dirname(plugin_basename(__FILE__)), '/'));

if (!defined('MYPLUGIN_PLUGIN_DIR'))
    define('MYPLUGIN_PLUGIN_DIR', WP_PLUGIN_DIR . '/' . MYPLUGIN_PLUGIN_NAME);

if (!defined('MYPLUGIN_PLUGIN_URL'))
    define('MYPLUGIN_PLUGIN_URL', WP_PLUGIN_URL . '/' . MYPLUGIN_PLUGIN_NAME);

Having these global paths defined lets me write the code below in my plugin anywhere I need to, and I know it will resolve correctly for any website that uses the plugin:

$image = MYPLUGIN_PLUGIN_URL . '/images/my-image.jpg';
$style = MYPLUGIN_PLUGIN_URL . '/css/my-style.css';
$script = MYPLUGIN_PLUGIN_URL . '/js/my-script.js';

Store the Plugin Version for Upgrades

When it comes to WordPress plugins, one of the things you’ll have to deal with sooner or later is upgrades. For instance, let’s say the first version of your plugin required one database table, but the next version requires another table. How do you know if you should run the code that creates the second database table?

I suggest storing the plugin version in the WordPress database so that you can read it later to decide certain upgrade actions your plugin should take. To do this, you’ll need to create a couple more global variables and invoke the add_option() function:

if (!defined('MYPLUGIN_VERSION_KEY'))
    define('MYPLUGIN_VERSION_KEY', 'myplugin_version');

if (!defined('MYPLUGIN_VERSION_NUM'))
    define('MYPLUGIN_VERSION_NUM', '1.0.0');

add_option(MYPLUGIN_VERSION_KEY, MYPLUGIN_VERSION_NUM);

I certainly could have simply called add_option('myplugin_version', '1.0.0'); without the need for the global variables, but like the global path variables, I’ve found these just as handy for using in other parts of a plugin, such as a Dashboard or About page.

Also note that update_option() could have been used instead of add_option(). The difference is that add_option() does nothing if the option already exists, whereas update_option() checks to see if the option already exists, and if it doesn’t, it will add the option to the database using add_option(); otherwise, it updates the option with the value provided.

Then, when it comes time to check whether or not to perform upgrade actions, your plugin will end up with code that looks similar to this:

$new_version = '2.0.0';

if (get_option(MYPLUGIN_VERSION_KEY) != $new_version) {
    // Execute your upgrade logic here

    // Then update the version value
    update_option(MYPLUGIN_VERSION_KEY, $new_version);
}

Use dbDelta() to Create/Update Database Tables

If your plugin requires its own database tables, you will inevitably need to modify those tables in future versions of your plugin. This can get a bit tricky to manage if you’re not careful, but WordPress helps alleviate this problem by providing the dbDelta() function.

A useful feature of the dbDelta() function is that it can be used for both creating and updating tables, but according to the WordPress codex page “Creating Tables with Plugins”, it’s a little picky:

  • You have to put each field on its own line in your SQL statement.
  • You have to have two spaces between the words PRIMARY KEY and the definition of your primary key.
  • You must use the keyword KEY rather than its synonym INDEX and you must include at least one KEY.

Knowing these rules, we can use the function below to create a table that contains an ID, a name, and an email:

function myplugin_create_database_table() {
    global $wpdb;
    $table = $wpdb->prefix . 'myplugin_table_name';

    $sql = "CREATE TABLE " . $table . " (
              id INT NOT NULL AUTO_INCREMENT,
              name VARCHAR(100) NOT NULL DEFAULT '',
              email VARCHAR(100) NOT NULL DEFAULT '',
              UNIQUE KEY id (id)
              );";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

Important: The dbDelta() function is found in wp-admin/includes/upgrade.php, but it has to be included manually because it’s not loaded by default.

So now we have a table, but in the next version we need to expand the size of the name column from 100 to 250. Fortunately dbDelta() makes this straightforward, and using our upgrade logic previously, the next version of the plugin will have code similar to this:

$new_version = '2.0.0';

if (get_option(MYPLUGIN_VERSION_KEY) != $new_version) {
    myplugin_update_database_table();
    update_option(MYPLUGIN_VERSION_KEY, $new_version);
}

function myplugin_update_database_table() {
    global $wpdb;
    $table = $wpdb->prefix . 'myplugin_table_name';

    $sql = "CREATE TABLE " . $table . " (
              id INT NOT NULL AUTO_INCREMENT,
              name VARCHAR(250) NOT NULL DEFAULT '', // Bigger name column
              email VARCHAR(100) NOT NULL DEFAULT '',
              UNIQUE KEY id (id)
              );";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

While there are other ways to create and update database tables for your WordPress plugin, it’s hard to ignore the flexibility of the dbDelta() function.

Know the Difference Between include, include_once, require, and require_once

There will come a time during the development of your plugin where you will want to put code into other files so that maintaining your plugin is a bit easier. For instance, a common practice is to create a functions.php file that contains all of the shared functions that all of the files in your plugin can use.

Let’s say your main plugin file is named myplugin.php and you want to include the functions.php file. You can use any of these lines of code to do it:

include 'functions.php';
include_once 'functions.php';

require 'functions.php';
require_once 'functions.php';

But which should you use? It mostly depends on your expected outcome of the file not being there.

  • include: Includes and evaluates the specified file, throwing a warning if the file can’t be found.
  • include_once: Same as include, but if the file has already been included it will not be included again.
  • require: Includes and evaluates the specified file (same as include), but instead of a warning, throws a fatal error if the file can’t be found.
  • require_once: Same as require, but if the file has already been included it will not be included again.

My experience has been to always use include_once because a) how I structure and use my files usually requires them to be included once and only once, and b) if a required file can’t be found I don’t expect parts of the plugin to work, but it doesn’t need to break anything else either.

Your expectations may vary from mine, but it’s important to know the subtle differences between the four ways of including files.

Use bloginfo(‘wpurl’) Instead of bloginfo(‘url’)

By and large, WordPress is installed in the root folder of a website; it’s standard operating procedure. However, every now and then you’ll come across websites that install WordPress into a separate subdirectory under the root. Seems innocent enough, but the location of WordPress is critically important.

To demonstrate, in the “General Settings” section of the WordPress admin panel, you’ll find the “WordPress address (URL)” and “Site address (URL)” settings, and for sites where WordPress is installed into the root directory, they will have the exact same values:

General-settings-same-url in Ten Things Every WordPress Plugin Developer Should Know

But for sites where WordPress is installed into a subdirectory under the root (in this case a “wordpress” subdirectory), their values will be different:

General-settings-different-url in Ten Things Every WordPress Plugin Developer Should Know

At this stage it’s important to know the following:

  • bloginfo(‘wpurl’) equals the “WordPress address (URL)” setting
  • bloginfo(‘url’) equals the “Site address (URL)” setting

Where this matters is when you need to build URLs to certain resources or pages. For example, if you want to provide a link to the WordPress login screen, you could do this:

// URL will be http://mydomain.com/wp-login.php
<a href="<?php bloginfo('url') ?>/wp-login.php">Login</a>

But that won’t resolve to the correct URL in the scenario such as the one above where WordPress is installed to the “wordpress” subdirectory. To do this correctly, you must use bloginfo('wpurl') instead:

// URL will be http://mydomain.com/wordpress/wp-login.php
<a href="<?php bloginfo('wpurl') ?>/wp-login.php">Login</a>

Using bloginfo('wpurl') instead of bloginfo('url') is the safest way to go when building links and URLs inside your plugin because it works in both scenarios: when WordPress is installed in the root of a website and also when it’s installed in a subdirectory. Using bloginfo('url') only gets you the first one.

How and When to Use Actions and Filters

WordPress allows developers to add their own code during the execution of a request by providing various hooks. These hooks come in the form of actions and filters:

  • Actions: WordPress invokes actions at certain points during the execution request and when certain events occur.
  • Filters: WordPress uses filters to modify text before adding it to the database and before displaying it on-screen.

The number of actions and filters is quite large, so we can’t get into them all here, but let’s at least take a look at how they are used.

Here’s an example of how to use the admin_print_styles action, which allows you to add your own stylesheets to the WordPress admin pages:

add_action('admin_print_styles', 'myplugin_admin_print_styles');

function myplugin_admin_print_styles() {
    $handle = 'myplugin-css';
    $src = MYPLUGIN_PLUGIN_URL . '/styles.css';

    wp_register_style($handle, $src);
    wp_enqueue_style($handle);
}

And here’s how you would use the the_content filter to add a “Follow me on Twitter!” link to the bottom of every post:

add_filter('the_content', 'myplugin_the_content');

function myplugin_the_content($content) {
    $output = $content;
    $output .= '<p>';
    $output .= '<a href="http://twitter.com/username">Follow me on Twitter!</a>';
    $output .= '</p>';
    return $output;
}

It’s impossible to write a WordPress plugin without actions and filters, and knowing what’s available to use and when to use them can make a big difference. See the WordPress codex page “Plugin API/Action Reference” for the complete list of actions and the page “Plugin API/Filter Reference” for the complete list of filters.

Tip: Pay close attention to the order in which the actions are listed on its codex page. While not an exact specification, my experimentation and trial-and-error has shown it to be pretty close to the order in which actions are invoked during the WordPress request pipeline.

Add Your Own Settings Page or Admin Menu

Many WordPress plugins require users to enter settings or options for the plugin to operate properly, and the way plugin authors accomplish this is by either adding their own settings page to an existing menu or by adding their own new top-level admin menu to WordPress.

How to Add a Settings Page

A common practice for adding your own admin settings page is to use the add_menu() hook to call the add_options_page() function:

add_action('admin_menu', 'myplugin_admin_menu');

function myplugin_admin_menu() {
    $page_title = 'My Plugin Settings';
    $menu_title = 'My Plugin';
    $capability = 'manage_options';
    $menu_slug = 'myplugin-settings';
    $function = 'myplugin_settings';
    add_options_page($page_title, $menu_title, $capability, $menu_slug, $function);
}

function myplugin_settings() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Here is where you could start displaying the HTML needed for the settings
    // page, or you could include a file that handles the HTML output for you.
}

By invoking the add_options_page() function, we see that the “My Plugin” option has been added to the built-in Settings menu in the WordPress admin panel:

Admin-menu-options-page in Ten Things Every WordPress Plugin Developer Should Know

The add_options_page() function is really just a wrapper function on top of the add_submenu_page() function, and there are other wrapper functions that do similar work for the other sections of the WordPress admin panel:

  • add_dashboard_page()
  • add_posts_page()
  • add_media_page()
  • add_links_page()
  • add_pages_page()
  • add_comments_page()
  • add_theme_page()
  • add_plugins_page()
  • add_users_page()
  • add_management_page()

How to Add a Custom Admin Menu

Those wrapper functions work great, but what if you wanted to create your own admin menu section for your plugin? For example, what if you wanted to create a “My Plugin” admin section with more than just the Settings page, such as a Help page? This is how you would do that:

add_action('admin_menu', 'myplugin_menu_pages');

function myplugin_menu_pages() {
    // Add the top-level admin menu
    $page_title = 'My Plugin Settings';
    $menu_title = 'My Plugin';
    $capability = 'manage_options';
    $menu_slug = 'myplugin-settings';
    $function = 'myplugin_settings';
    add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function);

    // Add submenu page with same slug as parent to ensure no duplicates
    $sub_menu_title = 'Settings';
    add_submenu_page($menu_slug, $page_title, $sub_menu_title, $capability, $menu_slug, $function);

    // Now add the submenu page for Help
    $submenu_page_title = 'My Plugin Help';
    $submenu_title = 'Help';
    $submenu_slug = 'myplugin-help';
    $submenu_function = 'myplugin_help';
    add_submenu_page($menu_slug, $submenu_page_title, $submenu_title, $capability, $submenu_slug, $submenu_function);
}

function myplugin_settings() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Render the HTML for the Settings page or include a file that does
}

function myplugin_help() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Render the HTML for the Help page or include a file that does
}

Notice that this code doesn’t use any of the wrapper functions. Instead, it calls add_menu_page() (for the parent menu page) and add_submenu_page() (for the child pages) to create a separate “My Plugin” admin menu that contains the Settings and Help pages:

Admin-menu-custom in Ten Things Every WordPress Plugin Developer Should Know

One advantage of adding your own custom menu is that it’s easier for users to find the settings for your plugin because they aren’t buried within one of the built-in WordPress admin menus. Keeping that in mind, if your plugin is simple enough to only require a single admin page, then using one of the wrapper functions might make the most sense. But if you need more than that, creating a custom admin menu is the way to go.

Provide a Shortcut to Your Settings Page with Plugin Action Links

In much the same way that adding your own custom admin menu helps give the sense of a well-rounded plugin, plugin action links work in the same fashion. So what are plugin action links? It’s best to start with a picture:

Plugin-action-links-none in Ten Things Every WordPress Plugin Developer Should Know

See the “Deactivate” and “Edit” links underneath the name of the plugin? Those are plugin action links, and WordPress provides a filter named plugin_action_links for you to add more. Basically, plugin action links are a great way to add a quick shortcut to your most commonly used admin menu page.

Keeping with our Settings admin page, here’s how we would add a plugin action link for it:

add_filter('plugin_action_links', 'myplugin_plugin_action_links', 10, 2);

function myplugin_plugin_action_links($links, $file) {
    static $this_plugin;

    if (!$this_plugin) {
        $this_plugin = plugin_basename(__FILE__);
    }

    if ($file == $this_plugin) {
        // The "page" query string value must be equal to the slug
        // of the Settings admin page we defined earlier, which in
        // this case equals "myplugin-settings".
        $settings_link = '<a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=myplugin-settings">Settings</a>';
        array_unshift($links, $settings_link);
    }

    return $links;
}

With this code in place, now when you view your plugins list you’ll see this:

Plugin-action-links-settings in Ten Things Every WordPress Plugin Developer Should Know

Here we provided a plugin action link to the Settings admin page, which is the same thing as clicking on Settings from our custom admin menu. The benefit of the plugin action link is that users see it immediately after they activate the plugin, thus adding to the overall experience.

Additional Resources

I’ve covered a lot in this article, but there’s plenty more out there to keep you busy awhile. The most comprehensive documentation for WordPress plugin development can be found on the WordPress Codex, a huge collection of pages documenting everything that is WordPress. Below are some of the more pertinent links from the codex you’ll need:

I also suggest reading Joost de Valk’s article “Lessons Learned From Maintaining a WordPress Plug-In“, which provides more good tips on WordPress plugin development.

(vf) (ik)


© Dave Donaldson for Smashing Magazine, 2011. | Permalink | Post a comment | Smashing Shop | Smashing Network | About Us
Post tags: Coding, development, plugin, wordpress

July 30 2010

16:09

Lessons Learned From Maintaining a WordPress Plug-In

Smashing-magazine-advertisement in Lessons Learned From Maintaining a WordPress Plug-InSpacer in Lessons Learned From Maintaining a WordPress Plug-In
 in Lessons Learned From Maintaining a WordPress Plug-In  in Lessons Learned From Maintaining a WordPress Plug-In  in Lessons Learned From Maintaining a WordPress Plug-In

Recently I released a WordPress plugin for Google Analytics that adds a tracking code and dozens of various pieces of meta data to blogs. Since the release of version 4, I’ve updated it 6 times, to the point where it’s now at version 4.0.6. In this article I would like to share with you my experiences in maintaining this and other WordPress plug-ins and common good practices that I’ve distilled from that work.

The updates that I released had a couple of purposes, ranging from bug fixes to new features and fixes in documentation. While all of these are nice to talk about, the bug fixes are the ones you’ll learn the most from, so let’s start by going through these.

Website and Account Configuration

Almost as soon as I released the plug-in, people who updated were telling me that it worked wonderfully, and others were telling me that it didn’t work for them. Turns out I hadn’t tested the plug-in with a Google Analytics account that has only one website registered; I expected the websites to be an array. Fixing this bug was easy, but determining that this was the problem took a while.

Being able to log into a few hosts of people who gave me access to their back end and FTP so that I could test my fix proved invaluable. This enabled me to release 4.0.1 within an hour of the 4.0 release.

Another mistake I made was forcing everyone to reconfigure the plug-in. I assumed it wouldn’t be too much work for people, and it wanted to be sure the settings were clean, but it turns out quite a few people didn’t want to reconfigure. With 4.0.2, I came up with a way to inherit some of the settings and clean up the mess I made, and in 4.0.4 I made a change that I will add to all of my plug-ins:

Analytics1 in Lessons Learned From Maintaining a WordPress Plug-In
Large view

Good practice #1: Don’t assume anything about people’s websites and external accounts.

Versioning Option Arrays

As a seasoned WordPress developer, I store all of the options for my plug-in in one option in the database, which is basically a big array. Why I hadn’t ever added a version number to these options is a mystery to me. Doing so makes it possible to do some very cool things: I can now add new features and set a default for these new features as soon as a user upgrades; I can show the user different messages based on the version they had before they upgraded; and more.

Good practice #2: Add a version number to your option arrays.

I’m still not using the WordPress option API stuff (check out this post by Ozh to learn all about it), which I probably should, but for now I find it easier to handle the saving and validation of options myself.

Don’t Release Too Soon

If you’ve got a bug that’s bugging a lot of your plug-in’s users, you’ll probably want to release a bug fix as soon as possible. I know I do. This caused an issue with my 4.0.3 release, though, because I didn’t properly test some of the code I introduced, causing me to have to release 4.0.4 just two hours later to fix a stupid mistake I’d made with booleans. Nothing is as painful as 500 people downloading a version of your plug-in that doesn’t actually work.

Good practice #3: Test, test, test before you release, even when you’re in a hurry.

Know Which Version People Are On

Over the past two weeks, I’ve been helping several people who said they were on the latest version of my plug-in but in fact were not. To remedy this, I’ve started outputting the version number in the comment that the plug-in outputs before the tracking code. Problem is, if people run a plug-in such as W3 Total Cache (which everyone should use by the way) or anything else that minifies their output, that comment will get lost.

There’s a solution for that, too: I’d already wrapped the script in <CDATA> tags, to help with Strict XHTML validation. Minifying will not occur within those CDATA tags, so I moved my “branding” comment to the CDATA section, and I can now always see, first, that my plug-in is active and, secondly, which version of the plug-in they’re using.

Good practice #4: Make sure you can see which version of your plug-in people are running.

URLs in WordPress

One of these things that can generate pretty awful bugs is a blog’s URL. Whether it’s due to people running their entire blog on https or “simply” running their blog in a sub-directory, it can cause headaches. It did for me in version 4.0.2 when I added URL sanitization: all relative URLs in posts and text widgets starting with a / were made absolute, in order to properly track these URLs. Tiny issue: I forgot about blogs in sub-directories, so a tiny portion of people would end up with links that used to go to /home but that now went to http://example.com/blog/home. I know, that was stupid; but that’s why I’m telling you: so you don’t make the same mistake.

Good practice #5: Make sure all URLs you use will work in all circumstances, whether WordPress is in a sub-directory, on a subdomain or just in the root.

Writing to the Root Directory

Somewhat related to the last issue, although I encountered this while developing my WordPress SEO plug-in, not the Google Analytics plug-in: if you write a file — say, an XML site map file — to the root of a website, and the website is actually a WordPress multi-site installation, things can go horribly wrong.

Check out the following scenario:

  1. User 1 writes and publishes a post on example.com/blog-1/.
  2. An updated XML site map for example.com/blog-1/ is generated, and example.com/sitemap.xml is updated.
  3. User 2 writes and publishes a post on example.com/blog-2/.
  4. An updated XML site map for example.com/blog-2/ is generated and example.com/sitemap.xml is overwritten.

See what just happened? The XML site map now contains only the posts from blog-2… This is exactly why the wp-content directory was created. There’s hardly ever a need to put a file in the root of an installation, and by not doing so, you make it far easier to run your plug-in in a multi-site/WordPress MU environment.

Good practice #6: If you’re generating files, generate them in the wp-content directory of your blog. Do not write files to the root directory unless you absolutely, positively have to. And if you do have to do it, make sure it doesn’t go wrong when your plug-in is active on multiple blogs in the same multi-site instance.

Rethink Your Filters

On the day that I released 4.0, I got quite a few feature requests, ranging from very simple to somewhat more complex. One that came in quite rapidly and caught my eye happened to be quite simple: the user wanted the same outbound link that in my plug-in tracks the content of an article to track in text widgets. Because I don’t use text widgets that much, it never occurred to me to do this. It was a valuable lesson, though:

Excitign in Lessons Learned From Maintaining a WordPress Plug-In
Large view

Good practice #7: If you’re filtering content, try to filter it in as many places as you can, so that users get consistent results all over WordPress.

[By the way, did you know we have a free bi-weekly Email Newsletter? Subscribe now and get fresh short tips and tricks!]

Never Assume

It’s true for everything, I guess, but especially true for WordPress developers: never assume. The seven best practices above mostly boil down to abandoning all assumptions about states, URLs and locations, and even about people knowing which version of a plug-in they’re using. Take all these matters into your own hands; your plug-in will be the better for it!

(al)


© Joost de Valk for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: plugin, wordpress

July 05 2010

21:00

jQuery Carousel Plugins: Best Resources, Tutorials And Examples

Preview-jquery-carousel-plugins-resources-tutorials-examplesCarousels are handy if you have a row images and want your visitors to access them  in solid and really beautiful way. With jQuery opportunities this feature is made very simple and good-looking.

In this post you’re going to find different types of premade carousel plugins and tutorials how to make your own unique carousel gallery whenever you wish, find also some little inspiration at the end of article as bonus!

1. jCarousel

jCarousel is a jQuery plugin for controlling a list of items in horizontal or vertical order. The items, which can be static HTML content or loaded with (or without) AJAX, can be scrolled back and forth (with or without animation). Check out 15+ examples, tutorial how to set it up and all configuration options. Works with all major browsers. Here’s the circular dynamic carousel example.

Jcarousel-jquery-carousel-plugins-resources-tutorials-examples

2. jCarousel Lite

jCarousel Lite is a jQuery plugin that carries you on a carousel ride filled with images and HTML content. jCarousel Lite is not a replacement for jCarousel; rather it is a light-weight (only 2kb) alternative for users whose primary focus is not to build a full-blown image gallery.

Lite-jquery-carousel-plugins-resources-tutorials-examples

3. Agile Carousel

Agile Carousel is a JQuery plugin that lets you create a carousel with flexible settings. Some cool features:

  • Ability to show multiple slides
  • Ability to show intro slide
  • Ability to Disable “First” and “Last” buttons at beginning & end of carousel

Here’s an example with intro slide.

Agile-beta--jquery-carousel-plugins-resources-tutorials-examples

4. jQuery Carrousel

The core allows to create your own controls or effects. This plugin transforms and tags into an animated carousel.

Js-jquery-carousel-plugins-resources-tutorials-examples

5. jQuery Infinite Carousel Plugin

jQuery carousel plugin where small image thumbnails allow users to jump over to other images.

Features:

  • Carousel never ends and images shuffle around
  • Captions are optional
  • Optional thumbnail controls which allow visitors to jump to any image in the carousel sequence
  • Thumbnails can be styled via CSS
  • It’s less than 14K
  • Reusable on multiple containers within the same page

Infinite-jquery-carousel-plugins-resources-tutorials-examples

6. Step Carousel Viewer

Step Carousel Viewer displays images or even rich HTML by side scrolling them left or right. Users can step to any specific panel on demand, or browse the gallery sequentially by stepping through x number of panels each time. A smooth sliding animation is used to transition between steps.

Step-viewer-jquery-carousel-plugins-resources-tutorials-examples

7. Just Another Carousel

A jQuery content carousel that works with any size content and supports mouse input. Features:

  • Works in FF3, IE7, Opera, and Safari.
  • Supports fixed-size or variable-size children
  • Supports the Meta plugin for jQuery
  • Totally CSS-based allowing for high customization
  • Degrades gracefully into an unordered list

Just-another-jquery-carousel-plugins-resources-tutorials-examples

8. LoopedCarousel

LoopedCarousel is a plugin made for jQuery that is not only a looping carousel, its main goal is to be extremely easy to implement. No more messing around with CSS to get your carousel to look and function properly. You want to show 5 items? Tell it “items: 5″ and so.

Looped-jquery-carousel-plugins-resources-tutorials-examples

9. jQuery Carousel

Great looking plugin with various types of use.

Great-jquery-carousel-plugins-resources-tutorials-examples

10. Roundabout

Roundabout is a jQuery plugin that converts a structure of static HTML elements into a highly customizable turntable-like interactive area. In its simplest configuration, Roundabout works with ordered- and unordered-lists, however after some quick configuration, Roundabout can work with a set of nested elements.

Roundabout-jquery-carousel-plugins-resources-tutorials-examples

11. How to Create a jQuery Carousel with WordPress Posts

This post will give you a quick run down of how to easily add a simple and easily customizable carousel with WordPress posts from a specified category.

How-to-create-with-wordpress-posts-jquery-carousel-plugins-resources-tutorials-examples

12. jQuery Carousel Gallery for WordPress

This plugin builds on the built-in WordPress gallery, and replaces any gallery inserted using the

tag with a neat jQuery powered carousel.

Gallery-for-wordpress-jquery-carousel-plugins-resources-tutorials-examples

13. Making an infinite JQuery carousel

In this tutorial you will make an infinite JQuery carousel. The infinite effect will be made by changing position of the items, when the user clicks right(next) the first item will be placed after the last item and when he clicks left(previous) the last item will be placed before the first item. You can check out the demo.

Making-infinite-jquery-carousel-plugins-resources-tutorials-examples

14. jQuery Infinite Carousel

Screencast how to create infinite jQuery carousel. Step by step written tutorial also available. Check out the demo and access code.

Screencast-tutorial-jquery-carousel-plugins-resources-tutorials-examples

Examples

Branded07

Branded-07-jquery-carousel-plugins-resources-tutorials-examples

Aaron Hall Portfolio

Aaron-hall-portfolio-jquery-carousel-plugins-resources-tutorials-examples

Corny

Corny-jquery-carousel-plugins-resources-tutorials-examples

Mkg Studio

Mkg-studio-jquery-carousel-plugins-resources-tutorials-examples

Deluge Studios

Deluge-studios-jquery-carousel-plugins-resources-tutorials-examples

Golf Working

Golf-working-jquery-carousel-plugins-resources-tutorials-examples

Dazzle Cat

Dazzle-cat-jquery-carousel-plugins-resources-tutorials-examples

What Is XV

What-is-xv-jquery-carousel-plugins-resources-tutorials-examples

Bret Glassett

Bret-glassett-jquery-carousel-plugins-resources-tutorials-examples

Chris Kaufman Portfolio

Chris-kaufman-portfolio-portfolio-jquery-carousel-plugins-resources-tutorials-examples

June 17 2010

17:14

How to Write a “Most Popular By Views” WordPress Plugin


As you continue writing for WordPress more and more, the level of difficulty and complexity of your plugins will eventually reach far beyond the simple back-end data manipulation, as demonstrated in our beginner’s article. In this installment we’ll cover in-depth: database interaction, Admin Widgets, and Sidebar Widgets. Today’s example will be a custom built “Most Popular by Views” plugin, which creates an admin area widget for us to view, and a sidebar widget for visitors to see.



Step 0. What it’s Gonna Do?

Before we open our IDE or write any code, you should always write out a list of what features your plugin will and will not have (at least in its initial phase, you can always extend later). For our plugin, “Most Popular By Views,” our primary feature is to display a list of the most popular posts (we’ll say, top 10). Secondly, we’ll also put the list in the admin area as a kind of low-tech analytics. Lastly, we’ll give the developers the option to display it anywhere by making it available as a sidebar widget, and via a simple function.

Features:

  • Creates a list of the top ten most popular posts based on views
  • List is displayed in Admin area as a low-tech analytics
  • List is available as both a sidebar widget and function
The finished widgets

Step 1. The Database

Before we can display the most popular posts, we need to gather data about which posts are being viewed and how often, but even before we can do that, we need somewhere to put all that data. Inside of a new plugin file, let’s create a new function (ppbv_create_table) that will check to see if our table exists. If it does not, we’ll create it. Our method of doing this is rather simple; we’ll use $wpdb->get_results to run a SQL statement that checks for a table named “wp_popular_by_views.” If it doesn’t find the table, get_results will return null. If that’s the case, we’ll use $wpdb->query to write in the new table. We run this function every time the plugin is activated.

<?php
/**
 * Plugin Name: Popular Posts by Views
 * Plugin URI: http://net.tutsplus.com
 * Description: Create a widget to show your most popular articles based on views.
 * Version: 1.0
 * Author: Jonathan Wolfe
 * Author URI: http://fire-studios.com
 * License: GPL2
 * .
 * This plugin and its accompanying tutorial are written for Nettuts+ at http://net.tutsplus.com
 * .
 */

global $wpdb; // call global so we can get the database prefix
$ppbv_tablename = $wpdb->prefix.'popular_by_views'; // combine the prefix with our tablename

function ppbv_create_table(){
    global $wpdb, $ppbv_tablename; // call global so we can use them within the function
    $ppbv_table = $wpdb->get_results("SHOW TABLES LIKE '{$ppbv_tablename}'" , ARRAY_N); // returns null if no results
    if(is_null($ppbv_table)){ // if we don't have a table
        $create_table_sql = "CREATE TABLE {$ppbv_tablename} (
            id BIGINT(50) NOT NULL AUTO_INCREMENT,
            post_id VARCHAR(255) NOT NULL,
            views BIGINT(50) NOT NULL,
            PRIMARY KEY (id),
            UNIQUE (id)
        );"; // be careful with SQL syntax, it can be VERY finiky
        $wpdb->query($create_table_sql); // run the SQL statement on the database
    }
}
register_activation_hook(__FILE__,'ppbv_create_table'); // run the function 'ppbv_create_table' at plugin activation
?>

Step 2. Catching the Data

The next thing we need to do, now that we have a table to store our data, is catch our data. We’ll create a new function (ppbv_page_viewed) that we’ll attach to the wp_head hook so that it’ll run on every page load. Inside this function, we’re going to do one of two things, after we check to see if the current page is already in the database: increase its views by one or, if it’s not in the database, add it to the database. To figure out if the current page is already in the database, we’re going to be using the $post object to get the “post_ID.” This step is actually really simple, because we aren’t collecting any complicated data; the comments in the code provide a detailed step by step in this process.

function ppbv_page_viewed(){
    if(is_single() && !is_page()){ // only run on posts and not pages
        global $wpdb, $post, $ppbv_tablename; // call global for use in funciton
        $wpdb->flush(); // clense the DB interface
        $data = $wpdb->get_row("SELECT * FROM {$ppbv_tablename} WHERE post_id='{$post->ID}'", ARRAY_A); // get the data row that has the matching post ID
        if(!is_null($data)){ // if we have a matching data row
            $new_views = $data['views'] + 1; // increase the views by 1
            $wpdb->query("UPDATE {$ppbv_tablename} SET views='{$new_views}' WHERE post_id='{$post->ID}';"); // update the data row with the new views
            $wpdb->flush(); // clense the DB interface
        }
        else { // if we don't have a matching data row (nobody's viewed the post yet)
            $wpdb->query("INSERT INTO {$ppbv_tablename} (post_id, views) VALUES ('{$post->ID}','1');"); // add a new data row into the DB with the post ID and 1 view
            $wpdb->flush(); // clense the DB interface
        }
    }
}
add_action('wp_head','ppbv_page_viewed'); // attach ppbv_page_viewed to the wp_head hook
Database and views process

Step 3. Creating the Admin Widget

Next up, we’re going to use this data we just added to our database to create an ordered list inside of an Admin Area Dashboard Widget. This process involves two functions: the first (ppbv_admin_widget) to generate everything inside the widget, and second, (ppbv_add_admin_widget) to create the widget itself. Let’s start with the content function, pppbv_admin_widget. Firstly, since we’re making an ordered list, let’s echo out the opening tags for that. Then we’ll globalize the $wpdb and $ppbv_tablename vars so we can access the database and retrieve the ten most viewed post’s IDs. Then we’ll run the returned array through a foreach statement, and use each individual ID to build a list-item and create a link to that page while also printing out its views (formatted with number_format to make it easier to read).

function ppbv_admin_widget(){
    echo "<ol id='popular_by_views_admin_list'>"; // create an unordered list
        global $wpdb, $ppbv_tablename; // call global for use in function
        $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
        foreach($popular as $post){ // loop through the returned array of popular posts
            $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
            $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
            $post_url = get_permalink($ID); // get the URL of the current post in the loop
            $title = get_the_title($ID); // get the title of the current post in the loop
            echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
        } // end the loop
    echo "</ol>"; // close out the unordered list
}

Now that we’re generating content, let’s create the widget. Inside the creation function, ppbv_add_admin_widget, we’re going to call another function native to WordPress: wp_add_dashboard_widget. All we need to do is give wp_add_dashboard_widget the following parameters: [id of the container], [title in the container], [content function] (ours fills as such: ‘popular_by_views’, ‘Most Popular Posts by Views’, ‘ppbv_admin_widget’). The last thing we need to do is attach our creation function to the wp_dashboard_setup hook.

function ppbv_add_admin_widget(){
    wp_add_dashboard_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_admin_widget'); // creates an admin area widget || wp_add_dashboard_widget([id of div],[title in div],[function to run inside of div])
}
add_action('wp_dashboard_setup','ppbv_add_admin_widget'); // attach ppbv_add_admin_widget to wp_dashboard_setup

And now we have a working dashboard widget for administraitors to see.

Admin Dashboard Widget

Step 4. Creating the Sidebar Widget

Creating a sidebar widget is fairly painless; unfortunately, certain parts aren’t documented well (like how to make them uniform), but we’ll cover that. Let’s start by writing a new function (ppbv_display_widget) and, inside of it, we’ll carbon copy our content function from the admin widget (I suggest moving the global calls to the top, outside the <ol> echo, of the function for clarity later on). Then the next step is to register our widget in WordPress via wp_register_sidebar_widget (parameters are: [id of the container],[title on the widget page],[content function] || ‘popular_by_views’, ‘Most Popular Posts by Views’, ‘ppbv_display_widget’).

function ppbv_display_widget() {
    global $wpdb, $ppbv_tablename; // call global for use in function

    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}
wp_register_sidebar_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_display_widget'); // add the widget to the select menu || wp_register_sidebar_widget([id of the option],[title of the option],[function to run from the widget]))

This is actually the bare-minimum you need to do for a sidebar widget, but what 90% of all dynamic sidebars have certain settings applied about how widgets are styled, so let’s conform our widget to those settings. The first thing we need to do is add in a parameter to our ppbv_display_widget function, $args. By adding this parameter inside the function, using the extract function on it, we gain access to several variables which will allow our plugin to be styled the same as the rest of the widgets in the sidebar.

“We don’t need to provide any input for $args, WordPress will do that for us.”

Thanks to $args and extract, we now have access to the following variables that we can echo to style our widget:

  • $before_widget
  • $after_widget
  • $before_title
  • $after_title
function ppbv_display_widget($args){
    global $wpdb, $ppbv_tablename; // call global for use in function
    extract($args); // gives us the default settings of widgets

    echo $before_widget; // echos the container for the widget || obtained from $args
        echo $before_title."Most Popular by Views".$after_title; // echos the title of the widget || $before_title/$after_title obtained from $args
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo $after_widget; // close the container || obtained from $args
}
Sidebar Widget

Step 5. The Non-widget Function

Not everybody who uses this plugin is going to want to use the widget, so it’s imperative that we provide them with another method of displaying our list. Thankfully, that’s as simple as cloning our ppbv_display_widget function and removing the widget parts, replacing them with standard hardcoded HTML.

function ppbv_display() {
    global $wpdb, $ppbv_tablename; // call global for use in function

    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}

Conclusion

That’s it guys, you’ve successfully made your very own “Most Popular by Views” WordPress plugin. Not too hard, was it?

When you’ve mastered the art of WordPress plugin development, stop by CodeCanyon.net and begin selling your plugins for profit!

View Final Source Code with Commenting?

<?php
/**
 * Plugin Name: Popular Posts by Views
 * Plugin URI: http://net.tutsplus.com
 * Description: Create a widget to show your most popular articles bassed on views.
 * Version: 1.0
 * Author: Jonathan Wolfe
 * Author URI: http://fire-studios.com
 * License: GPL2
 * .
 * This plugin and it's accompanying tutorial are written for NETTUTS at http://net.tutsplus.com
 * .
 */

global $wpdb; // call global so we can get the database prefix
$ppbv_tablename = $wpdb->prefix.'popular_by_views'; // combine the prefix with our tablename

function ppbv_create_table(){
    global $wpdb, $ppbv_tablename; // call global so we can use them within the function
    $ppbv_table = $wpdb->get_results("SHOW TABLES LIKE '{$ppbv_tablename}'" , ARRAY_N); // returns null if no results
    if(is_null($ppbv_table)){ // if we don't have a table
        $create_table_sql = "CREATE TABLE {$ppbv_tablename} (
            id BIGINT(50) NOT NULL AUTO_INCREMENT,
            post_id VARCHAR(255) NOT NULL,
            views BIGINT(50) NOT NULL,
            PRIMARY KEY (id),
            UNIQUE (id)
        );"; // be careful with SQL syntax, it can be VERY finiky
        $wpdb->query($create_table_sql); // run the SQL statement on the database
        $wpdb->flush(); // clense the DB interface
    }
}
register_activation_hook(__FILE__,'ppbv_create_table'); // run the function 'ppbv_create_table' at plugin activation

function ppbv_page_viewed(){
    if(is_single() && !is_page()){ // only run on posts and not pages
        global $wpdb, $post, $ppbv_tablename; // call global for use in funciton
        $wpdb->flush(); // clense the DB interface
        $data = $wpdb->get_row("SELECT * FROM {$ppbv_tablename} WHERE post_id='{$post->ID}'", ARRAY_A); // get the data row that has the matching post ID
        if(!is_null($data)){ // if we have a matching data row
            $new_views = $data['views'] + 1; // increase the views by 1
            $wpdb->query("UPDATE {$ppbv_tablename} SET views='{$new_views}' WHERE post_id='{$post->ID}';"); // update the data row with the new views
            $wpdb->flush(); // clense the DB interface
        }
        else { // if we don't have a matching data row (nobody's viewed the post yet)
            $wpdb->query("INSERT INTO {$ppbv_tablename} (post_id, views) VALUES ('{$post->ID}','1');"); // add a new data row into the DB with the post ID and 1 view
            $wpdb->flush(); // clense the DB interface
        }
    }
}
add_action('wp_head','ppbv_page_viewed'); // attach ppbv_page_viewed to the wp_head hook

function ppbv_admin_widget(){
    echo "<ol id='popular_by_views_admin_list'>"; // create an unordered list
        global $wpdb, $ppbv_tablename; // call global for use in function
        $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
        foreach($popular as $post){ // loop through the returned array of popular posts
            $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
            $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
            $post_url = get_permalink($ID); // get the URL of the current post in the loop
            $title = get_the_title($ID); // get the title of the current post in the loop
            echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
        } // end the loop
    echo "</ol>"; // close out the unordered list
}
function ppbv_add_admin_widget(){
    wp_add_dashboard_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_admin_widget'); // creates an admin area widget || wp_add_dashboard_widget([id of div],[title in div],[function to run inside of div])
}
add_action('wp_dashboard_setup','ppbv_add_admin_widget'); // attach ppbv_add_admin_widget to wp_dashboard_setup

function ppbv_display_widget($args){
    global $wpdb, $ppbv_tablename; // call global for use in function
    extract($args); // gives us the default settings of widgets

    echo $before_widget; // echos the container for the widget || obtained from $args
        echo $before_title."Most Popular by Views".$after_title; // echos the title of the widget || $before_title/$after_title obtained from $args
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo $after_widget; // close the container || obtained from $args
}
wp_register_sidebar_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_display_widget'); // add the widget to the select menu || wp_register_sidebar_widget([id of the option],[title of the option],[function to run from the widget]))

function ppbv_display() {
    global $wpdb, $ppbv_tablename; // call global for use in function

    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}
?>

May 12 2010

14:01

WordPress plugins on davidairey.com

WordPress logos

I’m frequently asked for advice about starting a blog. Many of you will know I use the freely available service WordPress to power both davidairey.com and Logo Design Love, but very few of you will know what WordPress plugins I’ve installed to help make the most of the publishing platform.

WordPress plugins installed here

  1. Akismet
    Comes as standard with all WordPress platform downloads, and checks reader comments against the Akismet web service to see if they look like spam. Those comments that do are automatically filtered into a “spam” folder.
  2. All in One SEO Pack
    Automatically optimises page titles and META tags for search engines. Easily override the predetermined titles and tags using form fields. In effect, you can have your post headlines say one thing e.g., “Are you serious?” and your page titles (usually the same as your headlines) say another e.g., “David Cameron new Prime Minister” for search engine rankings.
  3. cforms II
    Effortlessly creates easy-to-use web forms, sending the results to your chosen email address. I use this on my contact page, and when supplying potential clients with a few initial project questions.
  4. Facebook Like Widget
    I started testing this one a week or two ago. It adds a little “like” button beneath posts and pages, so if a reader is logged into Facebook, clicking the button will display the link on his/her wall for others to see. Not sure how well it’s going.
  5. Feedburner Feed Replacement
    Directs all feed URLs from WordPress to Feedburner (the third-party subscription service I use). It’s by Steve Smith of Ordered List, but the plugin is no longer available for download, so I’m curious if I should just deactivate this one. The FD Feedburner plugin looks like it does the same job, though, so maybe it’s worth keeping.
  6. Google XML Sitemaps
    Another for the search engines. It automatically generates and updates your sitemap, so search engine robots can easily and quickly crawl/index your content.
  7. Highlight Author Comments
    Allows me to self-style my own comments in every post thread, so mine appear slightly different from other commentators. Good for those who scan the threads looking for post-author replies.
  8. PostPost
    Particularly useful, and lets me add text and/or images to the foot of my RSS feed. I’ve added a line of text saying, “Published on David Airey, graphic designer” where the David Airey, graphic designer part links back to my homepage. This means all those splogs that scrape my feed and republish it without permission are giving a continual stream of links back to my site (it’s something, at least). I also display a banner advertising my book.
  9. Subscribe To Comments
    Adds a checkbox so commentators have the option to receive email updates when new comments are added after theirs. Hugely helpful for generating chat and a sense of community.
  10. WordPress.com Stats
    Google Analytics is great, but it’s too much for getting a quick look at where site visitors are coming from. This plugin puts an extra tab in the WordPress dashboard, and a single click shows the sites from which visitors arrive, what search engine terms are being used to direct traffic my way, popular posts, what people are clicking, and any new links to my site from elsewhere.
  11. WP-Cache
    Stores a static version of every page visited for a user-set time frame (up to one hour). This means that if I’m getting a sudden flood of traffic, the burden on my web host is greatly reduced (helping to prevent my site from going down).
  12. WordPress Related Posts
    You see the “Related posts on David Airey dot com” section below? That’s automatically generated by this plugin, helping increase clicks to other (normally related) pages on my site.
  13. WP Page Numbers
    Shows clickable page numbers at the foot of the homepage and category pages (instead of next page and previous page)
  14. WP Twitip ID
    Adds an extra field in the blog comment thread, allowing commentators to enter their Twitter ID for display. According to the plugin page, this one’s no longer supported, and has been replaced by the newer TwitterLink Comments.

It’s important to keep in mind that each plugin used will add to the loading time of your site. If I was half-decent at coding I’d probably do away with “WP Twitip ID” and “Highlight Author Comments” plugins, adding a piece of code to my blog theme instead.

Hopefully this short list has given the WordPress users out there a new idea or two.

Can you recommend any plugins you think would improve my collection?

WordPress buttons photo credit

Published on David Airey, graphic designer

Logo Design Love book

Related posts on David Airey dot com

April 08 2010

16:33

Fun with Canvas: Create a Bar Graphing Plugin, Part 2

In this two-part series, we’ll combine the versatile canvas element with the robust jQuery library to create a bar graphing plugin. In this second part, we are going to convert it in to a jQuery plugin, and then add some eye candy and additional features.

Concluding the Fun with canvas two-part series, today we are going to create a bar graphing plugin; not an ordinary plug in, mind you. We are going to show some jQuery love to the canvas element to create a very robust plugin.

In part one, we looked solely at implementing the logic of the plug in as a standalone script. At the end of part one, our bar graph looked like so.


Result at the end of Part 1

In this final part, we’ll work on converting our code and making it a proper jQuery plugin, adding some visual niceties and finally including some additional features. Ultimately, our output will look like so:


Finished product

All warmed up? Lets dive in!


Plugin Formalities

Before we start converting our code into a plugin we first need to look at a few formalities when it comes to plugin authoring.


Naming the Plugin

We begin by choosing a name for the plugin. I’ve chosen barGraph and renamed the JavaScript file to jquery.barGraph.js. We now enclose all the code from the previous article inside the following snippet.

$.fn.barGraph = function(settings) {
//code here
}

Settings contains all of the optional parameters passed to the plugin.


Working Around the $ Symbol Issue

In jQuery plugin authoring, it is generally considering a best practice to use jQuery instead of the $ alias in your code, in order to minimize conflicts with other Javascript libraries. Instead of going through all that trouble, we can just use custom aliases as mentioned in the jQuery docs. We enclose all our plugin code within this self executing anonymous function, as shown below:

(function($) {
$.fn.barGraph = function(settings) {
//plugin implementation code here
}
})(jQuery);

Essentially, we encapsulate all our code within a function and pass jQuery to it. We are free to use the $ alias as much as we want inside our code now, without having to worry about it potentially conflicting with other JavaScript libraries.


The Defaults

When designing a plugin, it is good sense to expose a reasonable number of settings to the user, whilst using sensible default options if the users uses the plugin without passing any options to it. With that in mind, we are going to enable the user to change each of the graph option variables I mentioned in this previous article in this series. Doing so is easy; we just define each of these variables as properties of an object and then access them.

var defaults = {
	         barSpacing = 20,
	 		 barWidth = 20,
	    	 cvHeight = 220,
			 numYlabels = 8,
			 xOffset = 20,
			 maxVal,
			 gWidth=550,
			 gHeight=200;
           }; 

We finally need to merge the default options with the passed options, giving preference to the passed ones. This line takes care of that.

var option = $.extend(defaults, settings);  

Do remember to change the variables names wherever necessary. As in –

return (param*barWidth)+((param+1)*barSpacing)+xOffset;

…changes to:

return (param*option.barWidth)+((param+1)*option.barSpacing)+option.xOffset;

Refactoring

This is where the plugin is hammered out. Our old implementation could only produce a single graph in a page, and the ability to create multiple graphs in a page is the main reason we are creating a plugin for this functionality. Plus, we need to make sure that the user doesn’t need to create a canvas element for every graph to be created. With that in mind, we are going to create the canvas elements dynamically as needed. Let’s proceed. We’ll look at the earlier and updated versions of the relevant portions of the code.


Invoking the Plugin

Before we start, I’d like to point out how our plugin will be invoked.

$("#years").barGraph
   ({
		 barSpacing = 30,
        barWidth = 25,
		 numYlabels = 12,
   });

Simple as that. years is the ID of the table holding all our values. We pass in the options as needed.


Obtaining the dataSource

To start things off, we first need a reference to the source of data for the graphs. We now access the source element and obtain its ID. Add the following line to the bunch of graph variables we declared earlier.

var dataSource = $(this).attr("id");

We define a new variable and assign it the value of the passed element’s ID attribute. Within our code, this refers to the currently selected DOM element. In our example, it refers to the table with an ID of years.

In the previous implementation, the ID for the data source was hard coded in. Now we replace that with the ID attribute we extracted earlier. The earlier version of the grabValues function is below:

function grabValues ()
	 {
	 	// Access the required table cell, extract and add its value to the values array.
		 $("#data tr td:nth-child(2)").each(function(){
		 gValues.push($(this).text());
	 	 });

		 // Access the required table cell, extract and add its value to the xLabels array.
		 $("#data tr td:nth-child(1)").each(function(){
	 	xLabels.push($(this).text());
	 	 });
	 } 

It is updated to this:

function grabValues ()
	 {
     	// Access the required table cell, extract and add its value to the values array.
	 	$("#"+dataSource+" tr td:nth-child(2)").each(function(){
		 gValues.push($(this).text());
	 	 });

		 // Access the required table cell, extract and add its value to the xLabels array.
		 $("#"+dataSource+" tr td:nth-child(1)").each(function(){
	 	xLabels.push($(this).text());
	 	 });
	 } 

Injecting the Canvas Element

function initCanvas ()
	 {
		 $("#"+dataSource).after("<canvas id=\"bargraph-"+dataSource+"\" class=\"barGraph\"> </canvas>");

         // Try to access the canvas element
     	cv = $("#bargraph-"+dataSource).get(0);

	 	if (!cv.getContext)
	 	{ return; }

     	// Try to get a 2D context for the canvas and throw an error if unable to
     	ctx = cv.getContext('2d');
	 	if (!ctx)
	 	{ return; }
	 }

We create a canvas element and inject it into the DOM after the table, which acts as the data source. jQuery’s after function comes in really handy here. A class attribute of barGraph and an ID attribute in the format barGraph-dataSourceID is also applied to enable the user to style them all as a group or individually as needed.


Cycling through the passed elements

There are two ways you could invoke this plugin actually. You could either create each graph separately passing in only one data source or you could pass in a number of sources. In the latter case, our current construct will encounter an error and quit. To rectify this, we use the each construct to iterate over the set of passed elements.

(function($){
	$.fn.barGraph = function(settings) {

	// Option variables
	var defaults = {
	         // options here
           };  

	// Merge the passed parameters with the defaults
    var option = $.extend(defaults, settings);  

	// Cycle through each passed object
	this.each(function() { 

	// Implementation code here
	});

	// Returns the jQuery object to allow for chainability.
	return this;
	}
})(jQuery);

We encapsulate all code after obtaining and merging the settings inside the this.each construct. We also make sure to return the jQuery object at the end to enable chainability.

With this, our refactoring is complete. We should be able to invoke our plugin and create as many graphs as needed.


Adding Eye Candy

Now that our conversion is complete, we can work on making it visually better. We are going to do a number of things here. We’ll look at each of them separately.


Themes

The older version used a bland gray to draw the graphs. We are going to implement a theming mechanism for the bars now. This, by itself, consists of a series of steps.


Ocean: The default theme

Foliage

Cherry Blossom

Spectrum

Adding it to the Options

var defaults = {
             // Other defaults here
	 	 	 theme: "Ocean",
           }; 

We add a theme option to the defaults enabling the user to change the theme to any of the four presets available.

Setting the Currently Selected Theme

function grabValues ()
	 {
	 	// Previous code

		switch(option.theme)
		{
			case 'Ocean':
			gTheme = thBlue;
			break;
			case 'Foliage':
			gTheme = thGreen;
			break;
			case 'Cherry Blossom':
			gTheme = thPink;
			break;
			case 'Spectrum':
			gTheme = thAssorted;
			break;
		}
	 }  

A simple switch construct looks at the option.theme setting and points the gTheme variable to the necessary colours array. We use descriptive names for the themes instead of generic ones.

Defining the Colours Array

// Themes
	var thPink = ['#FFCCCC','#FFCCCC','#FFC0C0','#FFB5B5','#FFADAD','#FFA4A4','#FF9A9A','#FF8989','#FF6D6D'];
	var thBlue = ['#ACE0FF','#9CDAFF','#90D6FF','#86D2FF','#7FCFFF','#79CDFF','#72CAFF','#6CC8FF','#57C0FF'];
	var thGreen = ['#D1FFA6','#C6FF91','#C0FF86','#BCFF7D','#B6FF72','#B2FF6B','#AAFE5D','#A5FF51','#9FFF46'];
	var thAssorted = ['#FF93C2','#FF93F6','#E193FF','#B893FF','#93A0FF','#93D7FF','#93F6FF','#ABFF93','#FF9B93']; 

We then define a number of arrays, each holding a series of shades of a specific colours. They start off with the lighter hue and keep on increasing. We’ll loop through these arrays later. Adding themes is as simple as adding an array for the specific colour you need, and then modifying the earlier switch to reflect the changes.

The Helper Function

function getColour (param)
      {
         return Math.ceil(Math.abs(((gValues.length/2) -param)));
	  } 

This is a tiny function which lets us achieve and apply a gradient like effect to the graphs. Essentially, we compute the absolute difference between half of the number of values to be rendered and the passed parameter, which is the index of the currently selected item in the array. This way, we are able to create a smooth gradient. Since we’ve only defined nine colours in each of the colours array, we are limited to eighteen values a graph. Extending this number should be fairly trivial.

Setting the fillStyle

function drawGraph ()
	 {
	    for(index=0; index<gValues.length; index++)
	      {
		    ctx.save();
			ctx.fillStyle = gTheme[getColour(index)];
	        ctx.fillRect( x(index), y(gValues[index]), width(), height(gValues[index]));
		    ctx.restore();
	      }
	 }

This is where we actually theme the graphs. Instead of setting a static value to the fillStyle property, we use the getColour function to retrieve the necessary index of the element in the currently selected theme’s array.


Opacity

Next up, we are going to give the user the ability to control the opacity of the bars drawn. Settings this is a two-step process.


With no transparency

With a value of 0.8

Adding it to the Options

var defaults = {
            // Other defaults here
	 	 	 barOpacity : 0.8,
           }; 

We add a barOpacity option to the defaults, enabling the user to change the opacity of the graphs to a value from 0 to 1, where 0 is completely transparent, and 1 is completely opaque.

Setting the globalAlpha

function drawGraph ()
	 {
	    for(index=0; index<gValues.length; index++)
	      {
		    ctx.save();
			ctx.fillStyle = gTheme[getColour(index)];
            ctx.globalAlpha = option.barOpacity;
	        ctx.fillRect( x(index), y(gValues[index]), width(), height(gValues[index]));
		    ctx.restore();
	      }
	 }

The globalAlpha property controls the opacity or transparency of the rendered element. We set this property’s value to the passed value or the default value to add a bit of transparency. As a sensible default, we use a value of 0.8 to make it just a tiny bit transparent.


Grid

A grid can be extremely useful in processing the data presented in a graph. Though I initially wanted a proper grid, I later settled for a series of horizontal lines lining up with the Y axis labels and completely threw away the vertical lines, since they just got in the way of the data. With that out of way, let’s go implement a way to render it.


With grid disabled

With grid enabled

Creating the lines using paths and the lineTo method seemed to be the most obvious solution for drawing the graphs, but I happened to run into a rendering bug which made this approach unsuitable. Hence I am sticking with the fillRect method to create these lines too. Here is the function in its entirety.

function drawGrid ()
      {
		  for(index=0; index<option.numYlabels; index++)
	      {
		   ctx.fillStyle = "#AAA";
		   ctx.fillRect( option.xOffset, y(yLabels[index])+3, gWidth, 1);
		  }
      }

This is very similar to drawing the Y axis labels, except that instead of rendering a label, we draw a horizontal line spanning the width of graph with a width of 1 px. The y function helps us in the positioning.

Adding it to the Options

var defaults = {
             // Other defaults here
	 	 	 disableGrid : false,
           }; 

We add a disableGrid option to the defaults, enabling the user to control whether a grid is rendered or not. By default, it is rendered.

    // Function calls
    	if(!option.disableGrid) { drawGrid(); }    

We just check whether the user wants the grid to be rendered and proceed accordingly.


Outlines

Now that the bars all are coloured, it lacks accent against a lighter background. To rectify this, we need a 1px stroke. There are two ways to do this. The first, and easiest, way would be to just add a strokeRect method to the drawGraph method; or, we could use the lineTo method to quickly stroke the rectangles. I chose the former route since as before the lineTo method threw some weird rendering bug at me.


With no stroking

With stroking

Adding it to Options

First we add it to the defaults object to give the user control of whether this is applied or not.

var defaults = {
             // Other defaults here
	 	 	 showOutline : true,
           }; 
function drawGraph ()
	 {
	       // Previous code
			if (option.showOutline)
			{
			ctx.fillStyle = "#000";
			ctx.strokeRect( x(index), y(gValues[index]), width(), height(gValues[index]));
			}
			// Rest of the code
	      }
	 }

We check whether the user wants to render the outlines, and, if yes, we proceed. This is almost the same as rendering the actual bars except that instead of using the fillRect method we use the strokeRect method.


Shading

In the original implementation, there is no differentiation between the canvas element itself, and the actual rendering space of the bars. We’ll rectify this now.


With no shading

With shading
function shadeGraphArea ()
      {
	    ctx.fillStyle = "#F2F2F2";
	    ctx.fillRect(option.xOffset, 0, gWidth-option.xOffset, gHeight);
      }

This is a tiny function which shades the required area. We cover the canvas element minus the area covered by the labels of both axes. The first two parameters point to the x and y coordinates of the starting point, and the last two point to the required width and height. By starting at option.offset, we eliminate the area covered by the Y axis labels, and by limiting the height to gHeight, we eliminate the X axis labels.


Adding Features

Now that our graph looks pretty enough, we can concentrate on adding some new features to our plugin. We’ll look at each separately.

Consider this graph of the famous 8K peaks.

When the highest value is sufficiently high enough, and most of the values fall within 10% of the maximum value, the graph ceases to be useful. We have two ways to rectify this.


ShowValue

We are going to start with the easier solution first. By rendering the value of the respective graphs at the top, the problem is virtually solved since the individual values can be easily differentiated. Here is how it is implemented.

var defaults = {
             // Other defaults here
	 	 	 showValue: true,
           }; 

First we add an entry to the defaults object to enable the user to switch it on and off at will.

    // Function calls
	if(option.showValue) { drawValue(); }

We check whether the user wants the value to be shown and proceed accordingly.

function drawValue ()
      {
		  for(index=0; index<gValues.length; index++)
	      {
		      ctx.save();
			  ctx.fillStyle= "#000";
			  ctx.font = "10px 'arial'";
			  var valAsString = gValues[index].toString();
		      var valX = (option.barWidth/2)-(valAsString.length*3);
		      ctx.fillText(gValues[index], x(index)+valX,  y(gValues[index])-4);
			  ctx.restore();
		  }
      } 

We iterate through the gValues array and render each value individually. The computations involving valAsString and valX are nothing but tiny calculations to aid us in the correct indentations, so it doesn’t look out of place.


Scale

This the harder of the two solutions. In this method, instead of starting the Y axis labels at 0, we start a lot closer to the minimum value. I’ll explain as we go. Do note that, in the above example, the difference between subsequent values with respect to the maximum value is pretty insignificant and doesn’t show its effectiveness as much. Other data sets should give easier to parse results.

Adding it to Options

var defaults = {
             // Other defaults here
	 	 	 scale: false
           }; 

Updating the Scale Function

Since the scale function is an integral part of the rendering process, we need to update it to allow the scaling feature. We update it like so:

function scale (param)
      {
	   return ((option.scale) ? Math.round(((param-minVal)/(maxVal-minVal))*gHeight) : Math.round((param/maxVal)*gHeight));
      }

I know this looks a little complicated, but it looks that way only due to use of the ternary conditional operator. Essentially, we check the value of option.scale and if it says false, the older code is executed. If it is true, instead of normalizing the value as a function of the maximum value in the array, we now normalize it to be a function of the difference between the maximum and minimum values. Which brings us to:

Updating the maxValues Function

We now need to find out both the maximum and minimum value, as opposed to only the maximum we had to before. The function is updated to this:

function minmaxValues (arr)
     {
		maxVal=0;

	    for(i=0; i<arr.length; i++)
	    {
		 if (maxVal<parseInt(arr[i]))
		 {
		 maxVal=parseInt(arr[i]);
	     }
	    }
		minVal=maxVal;
		for(i=0; i<arr.length; i++)
	    {
		 if (minVal>parseInt(arr[i]))
		 {
		 minVal=parseInt(arr[i]);
	     }
		}
	   maxVal*= 1.1;
       minVal = minVal - Math.round((maxVal/10));
	 }

I am sure you could accomplish the same in a single loop without using as many lines of code as me, but I was feeling particularly uncreative at that time so bear with me. With the calculation formalities out of the way, we issue a 5% increase to the maxVal variable and to the minVal variable, we subtract a value equal to 5% of maxVal’s value. This is to ensure the bars don’t touch the top everytime and the differences between each Y axis labels is uniform.

Updating the drawYlabels function

With all the groundwork done, we now proceed to update the Y axis label rendering routine to reflect the scaling.

function drawYlabels()
      {
		 ctx.save();
	     for(index=0; index<option.numYlabels; index++)
	      {
			  if (!option.scale)
			  {
		  		 yLabels.push(Math.round(maxVal/option.numYlabels*(index+1)));
			  }
			  else
			  {
				  var val= minVal+Math.ceil(((maxVal-minVal)/option.numYlabels)*(index+1));
		  		  yLabels.push(Math.ceil(val));
			  }
		   ctx.fillStyle = option.labelColour;
		   var valAsString = yLabels[index].toString();
		   var lblX = option.xOffset - (valAsString.length*7);
		   ctx.fillText(yLabels[index], lblX, y(yLabels[index])+10);
	      }
		   if (!option.scale)
		   {
	        	ctx.fillText("0", option.xOffset -7, gHeight+7);
		   }
		  else
		  {
		    var valAsString = minVal.toString();
		    var lblX = option.xOffset - (valAsString.length*7);
		    ctx.fillText(minVal, lblX, gHeight+7);
		  }
		  ctx.restore();
      } 

Pretty meaty update if you ask me! The core of the function remains the same. We just check whether the user has enabled scaling and branch off the code as needed. If enabled, we alter the way the Y labels are assigned to make sure they adhere to the new algorithm. Instead of the maximum value divided into n number of evenly spaced numbers, we now compute the difference between the maximum and minimum value, divide it into uniformly spaced numbers, and add it to the minimum value to build our array of Y axis labels. After this, we proceed as normal, rendering each label individually. Since we rendered the bottom-most 0 manually, we have to check whether scaling is enabled and then render the minimum value in its place. Don’t mind the small numerical additions to each passed parameter; it is just to make sure each element of the graph lines up as expected.


Dynamic Resizing

In our previous implementation, we hard coded the dimensions of the graph, which presents significant difficulty when the number of values change. We are going to rectify this now.

Adding it to the Options

var defaults = {
            // Other defaults here
	 	 	 cvHeight: 250, //In px
           }; 

We let the user set the height of the canvas element alone. All other values are calculated dynamically and applied as needed.

Updating the initCanvas Function

The initCanvas function handles all the canvas initialization, and, hence, needs to be updated to implement the new functionality.

function initCanvas ()
	 {
		 $("#"+dataSource).after("<canvas id=\"bargraph-"+dataSource+"\" class=\"barGraph\"> </canvas>");

	 	// Try to access the canvas element
     	cv = $("#bargraph-"+dataSource).get(0);
	 	cv.width=gValues.length*(option.barSpacing+option.barWidth)+option.xOffset+option.barSpacing;
		cv.height=option.cvHeight;
		gWidth=cv.width;
		gHeight=option.cvHeight-20;

	 	if (!cv.getContext)
	 	{ return; }

     	// Try to get a 2D context for the canvas and throw an error if unable to
     	ctx = cv.getContext('2d');
	 	if (!ctx)
	 	{ return; }
	 }

After injecting the canvas element, we obtain a reference to the created element. The canvas element’s width is calculated as a function of the number of elements in the array – gValues , the space between each bar – option.barSpacing, the width of each bar itself – option.barWidth and finally option.xOffset. The graph’s width changes dynamically based on each of these parameters. The height is user modifiable and defaults to 220px with the rendering area for the bar’s itself being 220px. The 20px is allocated to the X axis labels.


Hiding the Source

It makes sense that the user might want to hide the source table once the graph has been created . With this in mind, we let the user decide whether to remove the table or not.

var defaults = {
            // Other defaults here
			 hideDataSource: true,
           }; 
	if (option.hideDataSource) { $("#"+dataSource).remove();}

We check whether the user wants to hide the table and if yes, we remove it completely form the DOM using jQuery’s remove method.


Optimizing our Code

Now that all the hard work has been done, we can review how to optimize our code. Since this code has been written entirely for teaching purposes, most of the work has been encapsulated as separate functions and moreover they are a lot more verbose than they need to be.

If you really want the leanest code possible, our entire plugin, excluding the initialization and computation, can be rewritten within two loops. One looping through the gValues array to draw the bars themselves and the X axis labels; and the second loop iterating from 0 to numYlabels to render the grid and the Y axis labels. The code would look a lot messier, however, it should lead to a significantly smaller code base.


Summary

That’s it folks! We’ve created a high level plugin completely from scratch. We looked at a number of topics in this series including:

  • Looking at the canvas element’s rendering scheme.
  • Some of the canvas element’s rendering methods.
  • Normalizing values enabling us to express it as a function of another value.
  • Some useful data extraction techniques using jQuery.
  • The core logic of rendering the graph.
  • Converting our script to a full-fledged jQuery plugin.
  • How to enhance it visually and extend it even further feature-wise.

I hope you’ve had as much fun reading this as I had writing it. This being a 270-odd line work, I am sure I left out something. Feel free to hit the comments and ask me. Or criticize me. Or praise me. You know, it’s your call! Happy coding!


March 11 2010

21:00

5 Top jQuery Chart Libraries for Interactive Charts

Nowadays the need for an easy way to add interactive charts becomes essential because we are shifting from pc applications to web application. jQuery and other libraries allows to make accessible data visualization in (x)HTML, giving us this needed functionality.

In this article we are going to present 5 chart libraries that suit different needs from simple charts to high complex charts. Most of them are free for personal and commercial use.

1. jQuery Visualize Plugin

jQuery Visualize Plugin is the perfect plugin if you have a table and want to generate a chart out of it. It offers different types of charts such as Bar, Area, Pie & Line charts.
Examples

Type of Charts: Bar, Area, Pie & Line.
Requirements: jQuery, excanvas (included)
Browser Support: IE6*, IE7*, IE8*, Firefox 2, Firefox 3.5, Safari 3 and 4, Opera 9.
* HTML 5 canvas element is not supported by IE but Google maintains a library that translates canvas scripting into VML, allowing it to work in all versions of internet explorer.
Demo: http://www.filamentgroup.com/examples/charting_v2/index_2.php
License: MIT and GPL licenses

2. Highcharts

Highcharts is a really impressive jQuery Chart Library. In a few words Highcharts is compatible with most Browsers and even the iPhone; numerous chart types are supported; it is a dynamic plugin because you can add, remove and modify series, axes or points at any time after chart creation and you can load data from external files; tooltip labels are also supported which is great for detailed information in a point of a chart; zooming and last but not least all text labels can be rotated in any angle.
Examples

Line and column example

Columns with rotated labels

Type of Charts: Bar, Area, Areaspline , Pie, Line, Spline, Column & Scatter.
Requirements: jQuery or MooTools
Browser Support: IE6, IE7, IE8, Firefox 2, Firefox 3.5, Safari 3 and 4, Opera 9 and iPhone!
Demo: http://www.highcharts.com/demo/
License: Creative Commons Attribution  Non-Commercial 3.0 License. Free for personal website, a school site or a non-profit organization. For a single commercial Website the license costs $80.

3. Flot

Flot is as the authors call it an “Attractive Javascript plotting for jQuery” which is true. The charts look simple and nice, it is easy to create charts and all settings are optional. Some key features of plot is turning series on/off, zooming, interacting with the data points and it integrates a simple tooltip feature.
Examples

Tracking curves with crosshair plugin

Type of Charts: Bar, Area, Point & Line.
Requirements: jQuery
Browser Support: IE6, IE7, IE8, Firefox 2, Firefox 3.5, Safari 3 and 4, Opera 9 and Konqueror 4+.
Demo: http://people.iola.dk/olau/flot/examples/
License: MIT License

4. jQuery Sparklines

Sparklines generates small inline charts either inline in the HTML or via JavaScript. It is really good for displaying mini graphs notably because most of them just take 1 line of HTML or JavaScript code. Another great feature is it self-refreshing capabilities. You can see it in their Mouse-Speed demo which shows you the power of live charting.
Example

Type of Charts: Bar, Tristate, Bullet, Box Plot & Line.
Requirements: jQuery
Browser Support: IE6, IE7, IE8, Firefox 2, Firefox 3.5, Safari 3 and 4, Opera 9 and Google Chrome.
Demo: http://omnipotent.net/jquery.sparkline/
License: New BSD License

5. jqPlot

jqPlot did not catch my eye at first glance but after further research I found it to be one of the best and free jQuery chart library. Numerous graphical options are available you can even add shadows and interact per drag&drop in the charts! It even automatically computes trend lines. We could compare it to highcharts in terms of features and functionality.
Examples


Type of Charts: Bar, Pie & Line.
Requirements: jQuery
Browser Support: IE6, IE7, IE8, Firefox 2, Firefox 3.5, Safari 3 and 4, Opera 9 and Google Chrome.
Demo: http://www.jqplot.com/tests/
License: MIT and GPL version 2 licenses

Conclusion

As you may have seen from this 5 jQuery chart libraries they suit different needs. First Sparklines generates a small inline chart which is perfect for charts where the precision is not important. You look at the small chart and you should directly know what happened.

Highcharts, Flot and jqPlot are very powerful jQuery chart libraries. My personal favourites is Highcharts and jqPlot. The visual quality of Highcharts charts are better than jqPlot but the last one is free. I recommend you to test at least one of them and you will see that they are really powerful.

Finally jQuery Visualize is really easy to use and specially adapted if you want to create a chart out of a table, just like you would do it in excel. This can be convenient when you need a table and a chart to visualize your thoughts. Feel free to give your feedback via comments section.:)

December 27 2009

13:13

10 Popular jQuery Plugins in 2009 You Can’t Miss


Here is a collection of ten useful jQuery plugins of 2009 you can’t miss. If you have other interesting plugins to share, please leave a comment. Thanks!

jQuery Before/After

This plug-in shows the difference between two images simply dragging a slider over the two images which are sandwiched with one on top of the other. The final effect is really nice and easy to implement.

Take a look at this plug-in here. For the demos here.

Sunday Morning

Sunday Morning is a jQuery plugin which allows site-owner to offer their visitors some easy and fancy ways to translate their content in more then 30 languages.

jQTouch

jQTouch is a jQuery plugin for mobile web development on the iPhone, iPod Touch, and other forward-thinking devices. Absolutely to have if you are a mobile developer.

CJ Image Video Previewer

CJ Image Video Previewer is meant to mimic the video preview boxes you see on many Video sites. It displays a block that contains an image thumbnail and when the user moves their cursor of the box, it dynamically loads and then displays a group of images in sequence. Kind of like a flip-book. This is an excellent way to provide an preview of the video, without the user actually downloading the video file.

Autosave

Autosave is a flexible autosave plugin for jQuery. If yo want to autosave a form use this simple code:
$("form#myForm").autosave();.

MapBox

The jQuery MapBox plugin is for creating relatively small scale, zoomable, draggable maps with multiple layers of content. This framework could be applied to games, development plans, or any layout that could benefit from being able to zoom in and pan to get a better view.

Ajax Upload

AJAX Upload allows you to easily upload multiple files without refreshing the page and use any element to show file selection window. AJAX Upload doesn’t pollute the global namespace, so it’s compatible with jQuery, Prototypejs, Mootools, and other JavaScript libraries.

Infinite Scroll

Infinite Scroll has been called autopagerize, unpaginate, endless pages. But essentially it is pre-fetching content from a subsequent page and adding it directly to the user’s current page. This plugin aims to progressively enhance your page. Your navigation/pagination elements should be present in the HTML for non-js users, but the plugin will utilize those links to build out a more rich browsing experience (with this plug-in you can implement easily a DZone.com-like navigation experience).

jQuery Tools

jQuery Tools isn’t a plug-in but is a collection of the most important user-interface components for today’s websites (tabs, tooltips, overlay, drag-and-drop, exposé, scrollable, …).

jQuery lightBox

jQuery lightBox is probably one of the most popular an easy to implement jQuery light-box. This plugin is simple, elegant, unobtrusive, no need extra markup and is used to overlay images on the current page through the power and flexibility of jQuery’s selector.

November 29 2009

21:12

jQuery Lesson Series: How to Add Options to Plugins


Last time we learned building an optionless jQuery plugin. But without options, a plugin is nothing but a mere function. This time we are going to focus how to add options to a plugin and extend its functionality. Our sample plugin is going to be a tab navigation plugin. You can read the first part if you haven’t see the first part of this lesson.

For a printable reference guide to the jQuery API I suggest you to download this interesting jQuery Visual Cheat Sheet designed by Antonio Lupetti or take a look at the official jQuery documentation.

Now let’s start coding with our empty template.

(function($){
$.fn.woorkTabs = function(){
// all plugin stuff will be here
};
})(jQuery);

In a plugin, you can use options either with their predefined (default) values or with their newly assigned values. So for our default values, we need to add a definition part in our plugin.

(function($){
$.fn.woorkTabs = function(){
// all plugin stuff will be here
};

$.fn.woorkTabs.defaults = {
navigation: '#tabs a',
pages : '.page'
}
})(jQuery);

where $.fn.woorkTabs.defaults part is the default value for the options in the plugin. Each option can be defined as option_name : ‘option value’. For values like numbers or true false statements you do not need to use quotation marks e.g. option_name : true or option_name : 1500  There are two things to remember: you should always define a value with a semicolon ( : ) and every option should be separated by comma (,) from each other. But for our beloved internet explorer compatibility, you should remove comma after the last option.

After adding default option values, we need to call them in our plugin.

(function($){
$.fn.woorkTabs = function(options){
var $options = $.extend({}, $.fn.woorkTabs.defaults, options);
};

$.fn.woorkTabs.defaults = {
navigation: '#tabs a',
pages : '.page'
}
})(jQuery);

So we add a variable names $options to extend the plugin’s default options. This new extend() function merges the default settings with newly defined option values while calling the plugin. We can get this options by $options.option_name syntax for using them in the functions. Also notice that, we add a keyword options in the $.fn.woorkTabs = function(options) part to get the options new values while calling the plugin. After adding our  return this.each(function(){}); statement, initial setup for the plugin is finished.

(function($){
$.fn.woorkTabs = function(options){
var $options = $.extend({}, $.fn.woorkTabs.defaults, options);
return this.each(function(){
});
};

$.fn.woorkTabs.defaults = {
navigation: '#tabs a',
pages : '.page'
}
})(jQuery);

In our page we can call this plugin either with defaults or with new values like

$(target1).woorkTabs();

$(target2).woorkTabs({
navigation : '#tabnav a',
pages : '#example .pages'
});

Many of you know what a tabbed navigation is. The main idea is by clicking the links in a navigation list, target content become visible in the page and others become invisible.

Start with getting options,

var $navigation = $options.navigation;
var $pages = $options.pages;

Since the main idea is clicking something, we need to use click() event. This function triggers anything you defined inside the function when mouse clicked the target. In our case, when user clicks the tab, first plugin finds the target content, then hides other contents and shows the target. But first of all, let’s see how our html will look like.

<div id="tabs">

<ul>
    <li><a href="#tabcontent1">Tab Content 01</a></li>
    <li><a href="#tabcontent2">Tab Content 02</a></li>
    <li><a href="#tabcontent3">Tab Content 03</a></li>
</ul>

<div id="tabcontent1">
    <p>This the first tab page for example</p>
</div>
<div id="tabcontent2">
    <p>This the second tab page for example</p>
</div>
<div id="tabcontent3">
    <p>This the last tab page for example</p>
</div>
</div>

In the navigation list, all links represents our tabs and they are targeting the pages ids according to their href values. We can get the content’s id, which will be visible, easily by clicked tab’s href attribute.

$($navigation).click(function(){
var $e = $(this);
var $goingToShow = $e.attr('href');
});

As in the previous lesson $e variable is for calling freely the clicked element.  With the attr() function we can get any attribute’s value from the element. In this case, we need the href attributes. Notice that, the href value is start with “#” which indicates id in jQuery selectors, we can directly use the $goingToShow variable in the process. The following step is, showing the clicked tab’s content and hiding the other tabs’ contents. show() and hide() effects are the most appropriate functions for this work. show() function shows the element by setting it’s css display property to “block” and hide() function hides the element by setting it’s css display property to “hidden”.

$($navigation).click(function(event){
event.preventDefault();

var $e = $(this);
var $goingToShow = $e.attr('href');

$pages.hide();
$goingToShow.show();

$($navigation).removeClass('active');
$e.addClass('active');
});

We hide the all tab pages by $pages.hide() then show the clicked tab’s page. Also we remove the ‘active’ class from the tabs add add ‘active’ class to clicked tab to be able to define visual properties in css for our active tab. And lastly, for prevent jumping the page due to link fragment in our tab’s href attribute. Overall plugin is as follows

(function($){
$.fn.woorkTabs = function(options){
var $options = $.extend({}, $.fn.woorkTabs.defaults, options);

return this.each(function(){
var $navigation = $options.navigation;
var $pages = $options.pages;

$($navigation).click(function(event){
event.preventDefault();

var $e = $(this);
var $goingToShow = $e.attr('href');

$pages.hide();
$goingToShow.show();

$($navigation).removeClass('active');
$e.addClass('active');
});
};

$.fn.woorkTabs.defaults = {
navigation: '#tabs a',
pages : '.page'
}
})(jQuery);

Example

Here is the HTML code:

<div id="tabs">
<ul>
    <li><a href="#tabcontent1">Tab Content 01</a></li>
    <li><a href="#tabcontent2">Tab Content 02</a></li>
    <li><a href="#tabcontent3">Tab Content 03</a></li>
</ul>

<div id="tabcontent1">
    <p>This the first tab page for example</p>
</div>

<div id="tabcontent2">
    <p>This the second tab page for example</p>
</div>

<div id="tabcontent3">
    <p>This the last tab page for example</p>
</div>

</div>

JavaScript

Here is the JavaScript code:

$(function(){
$("#tabs").woorkTabs({
navigation: "#tabnav a"
});
});

Take a look at the live example here.

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...