(Reading time: 12 – 19 minutes)
I was talking to Julie Roads the other day about post slugs, and it occurred to me I haven’t written on post slugs for quite a while. In fact, while it’s on my mind, go visit Julie and get yourself some refresh and reload.
Now that you’ve wiped your slate clean, let’s reload it with Stuff You Need To Know. Like post slugs.
Although I discuss post slugs in Blog Post Engineering in some detail, much of what follows is new material. Some of this may go into the next release of Blog Post Engineering as well.
It turns out there exists a spiffy little plugin called “SEO Slugs,” which will:
- Help you create shorter, keyword-rich slugs using your article title.
- Will not automatically change your title, so you have ultimate control (as it should be).
The SEO Slugs plugin is very old and hasn’t been updated in years. I usually recommend NOT using older plugins (for good reason), but as you will see, there isn’t anything out of date in SEO Slugs. (That’s either a testament to the strength of WordPress design, or an indictment to it’s lack of innovation. I could argue both sides. I’ll spare us all.)
This plugin is cool, because you don’t really have to do anything, it just works quietly in the background:
Since it’s (Technical) Tuesday, it’s a perfect opportunity to get all hard core about it too. So I’m going to break this stepwise for you. You will see how I attack plugin problems, and how this particular plugin works to your benefit.
SEO Slugs plugin
First, if code makes your eyes glaze over, just skip right over to where I break this plugin down one piece at a time.
Since SEO Slugs is really short, I’m listing out all 43 lines right here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?php /* Plugin Name: SEO Slugs Plugin URI: http://www.vretoolbar.com/news/seo-slugs-wordpress-plugin Description: Removes common words like 'a', 'the', 'in' from post slugs to improve SEO. Version: 1.0 Author: Andrei Mikrukov Author URI: http://www.vretoolbar.com */ /* Copyright Andrei Mikrukov 2007 Licensed under the terms of the GPL version 2, see: http://www.gnu.org/licenses/gpl.txt Provided without warranty, inluding any implied warrant of merchantability or fitness for purpose. */ add_filter('name_save_pre', 'seo_slugs', 0); function seo_slugs($slug) { // We don't want to change an existing slug if ($slug) return $slug; global $wpdb; $seo_slug = strtolower(stripslashes($_POST['post_title'])); $seo_slug = preg_replace('/&.+?;/', '', $seo_slug); // kill HTML entities // kill anything that is not a letter, digit, space or apostrophe $seo_slug = preg_replace ("/[^a-zA-Z0-9 \']/", "", $seo_slug); // Turn it to an array and strip common words by comparing against c.w. array $seo_slug_array = array_diff (split(" ", $seo_slug), seo_slugs_stop_words()); // Turn the sanitized array into a string $seo_slug = join("-", $seo_slug_array); return $seo_slug; } function seo_slugs_stop_words () { return array ("a", "able", "about", "above", "abroad", "according", "accordingly", "across", "actually", "adj", "after", "afterwards", "again", "against", "ago", "ahead", "ain't", "all", "allow", "allows", "almost", "alone", "along", "alongside", "already", "also", "although", "always", "am", "amid", "amidst", "among", "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere", "apart", "appear", "appreciate", "appropriate", "are", "aren't", "around", "as", "a's", "aside", "ask", "asking", "associated", "at", "available", "away", "awfully", "b", "back", "backward", "backwards", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "begin", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond", "both", "brief", "but", "by", "c", "came", "can", "cannot", "cant", "can't", "caption", "cause", "causes", "certain", "certainly", "changes", "clearly", "c'mon", "co", "co.", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain", "containing", "contains", "corresponding", "could", "couldn't", "course", "c's", "currently", "d", "dare", "daren't", "definitely", "described", "despite", "did", "didn't", "different", "directly", "do", "does", "doesn't", "doing", "done", "don't", "down", "downwards", "during", "e", "each", "edu", "eg", "eight", "eighty", "either", "else", "elsewhere", "end", "ending", "enough", "entirely", "especially", "et", "etc", "even", "ever", "evermore", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "f", "fairly", "far", "farther", "few", "fewer", "fifth", "first", "five", "followed", "following", "follows", "for", "forever", "former", "formerly", "forth", "forward", "found", "four", "from", "further", "furthermore", "g", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got", "gotten", "greetings", "h", "had", "hadn't", "half", "happens", "hardly", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "hello", "help", "hence", "her", "here", "hereafter", "hereby", "herein", "here's", "hereupon", "hers", "herself", "he's", "hi", "him", "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "hundred", "i", "i'd", "ie", "if", "ignored", "i'll", "i'm", "immediate", "in", "inasmuch", "inc", "inc.", "indeed", "indicate", "indicated", "indicates", "inner", "inside", "insofar", "instead", "into", "inward", "is", "isn't", "it", "it'd", "it'll", "its", "it's", "itself", "i've", "j", "just", "k", "keep", "keeps", "kept", "know", "known", "knows", "l", "last", "lately", "later", "latter", "latterly", "least", "less", "lest", "let", "let's", "like", "liked", "likely", "likewise", "little", "look", "looking", "looks", "low", "lower", "ltd", "m", "made", "mainly", "make", "makes", "many", "may", "maybe", "mayn't", "me", "mean", "meantime", "meanwhile", "merely", "might", "mightn't", "mine", "minus", "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must", "mustn't", "my", "myself", "n", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needn't", "needs", "neither", "never", "neverf", "neverless", "nevertheless", "new", "next", "nine", "ninety", "no", "nobody", "non", "none", "nonetheless", "noone", "no-one", "nor", "normally", "not", "nothing", "notwithstanding", "novel", "now", "nowhere", "o", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on", "once", "one", "ones", "one's", "only", "onto", "opposite", "or", "other", "others", "otherwise", "ought", "oughtn't", "our", "ours", "ourselves", "out", "outside", "over", "overall", "own", "p", "particular", "particularly", "past", "per", "perhaps", "placed", "please", "plus", "possible", "presumably", "probably", "provided", "provides", "q", "que", "quite", "qv", "r", "rather", "rd", "re", "really", "reasonably", "recent", "recently", "regarding", "regardless", "regards", "relatively", "respectively", "right", "round", "s", "said", "same", "saw", "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self", "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "since", "six", "so", "some", "somebody", "someday", "somehow", "someone", "something", "sometime", "sometimes", "somewhat", "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "t", "take", "taken", "taking", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "that'll", "thats", "that's", "that've", "the", "their", "theirs", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "there'd", "therefore", "therein", "there'll", "there're", "theres", "there's", "thereupon", "there've", "these", "they", "they'd", "they'll", "they're", "they've", "thing", "things", "think", "third", "thirty", "this", "thorough", "thoroughly", "those", "though", "three", "through", "throughout", "thru", "thus", "till", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try", "trying", "t's", "twice", "two", "u", "un", "under", "underneath", "undoing", "unfortunately", "unless", "unlike", "unlikely", "until", "unto", "up", "upon", "upwards", "us", "use", "used", "useful", "uses", "using", "usually", "v", "value", "various", "versus", "very", "via", "viz", "vs", "w", "want", "wants", "was", "wasn't", "way", "we", "we'd", "welcome", "well", "we'll", "went", "were", "we're", "weren't", "we've", "what", "whatever", "what'll", "what's", "what've", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "where's", "whereupon", "wherever", "whether", "which", "whichever", "while", "whilst", "whither", "who", "who'd", "whoever", "whole", "who'll", "whom", "whomever", "who's", "whose", "why", "will", "willing", "wish", "with", "within", "without", "wonder", "won't", "would", "wouldn't", "x", "y", "yes", "yet", "you", "you'd", "you'll", "your", "you're", "yours", "yourself", "yourselves", "you've", "z", "zero"); } ?> |
Spiffy, right? I love little pieces of code like this. Pure poetry.
Let’s prise it apart and ponder it piecewise.
Let’s break it down
Once again, if you’re getting queasy, just skip right over this part to get to the goodies at the end.
And once again, why all this trouble? Couple of reasons: SEO Slugs is very short, so “Because I can” is really all the justification I need. But another, more important reason is that it illustrates a very important and powerful capability of WordPress, in a context that most intermediate WordPress bloggers can understand. That is, you. (And that includes you too Mr. El Dorado)
Start at the beginning…
…which is usually the best place to start.
In this case, on line 20 we’re kicking off with add_filter, one of the top five most important functions in WordPress. Dig into the WordPress code, add_filter is everywhere you look. Even with relatively benign functions such as register_activation_hook, scratch it deep enough, there’s a daggone add_filter lurking down in the basement.
20 | add_filter('name_save_pre', 'seo_slugs', 0); |
Here’s what add_filter does: it takes a function, here given by seo_slugs declared on line 22, and adds that function to the list of functions which get called when the name_save_pre template is invoked. That is, when you press “Save Draft,” the seo_slugs function processes your article title and emits a tasty new post slug full of keyword-rich scrumptiousness.
But suppose you like your post slug. It’s quite tasty enough, thank you. That’s cool, SEO Slugs will keeps it mitts to itself. Here’s proof:
24 25 | // We don't want to change an existing slug if ($slug) return $slug; |
All this means is that when you put your own slug in the little box, you get to keep it:
What’s next…
27 28 | global $wpdb; $seo_slug = strtolower(stripslashes($_POST['post_title'])); |
wpdb is your WordPress database. It’s another one of those things that’s everywhere, you need to make it’s acquaintance sooner or later.

The next function, strtolower takes your title and turns all your capital letters into lower case letters. Actually, it takes your title after it does a little magic on it with stripslashes, but let’s leave that rabbit hole for another day.
Next, if you have some of those cool HTML symbols in your title, like hearts ♥s and stuff ‽, we have to remove those for the post slug:
30 | $seo_slug = preg_replace('/&.+?;/', '', $seo_slug); // kill HTML entities |
preg_replace is easy: Perl-compatible regular expression, replace all matching instances.
You know how I always say, “Simple, but not easy”? Well, this is easy, but not simple.
Let’s get rid of more cruft people like me put in our blog post titles, like punctation marks, etc.
31 32 | // kill anything that is not a letter, digit, space or apostrophe $seo_slug = preg_replace ("/[^a-zA-Z0-9 \']/", "", $seo_slug); |
Self-explanatory, if you grok regular expressions. ^a-zA-Z0-9 means get rid of everything not a through z, A through Z or 0 through 9. Easy peasy. (But not simple.)
Here’s where we get to the good stuff. Our post slug is all prepped, now it’s time to strip out the stop words. Words like “a” and “the” and “and” which are boring and unrankable. Seriously, trying to rank for the word “the” would be pretty hard.
31 32 33 34 35 36 | // Turn it to an array and strip common words by comparing against c.w. array $seo_slug_array = array_diff (split(" ", $seo_slug), seo_slugs_stop_words()); // Turn the sanitized array into a string $seo_slug = join("-", $seo_slug_array); return $seo_slug; |
Picking up the pace, line 32 matches your title against an array of stop words, and deletes everything in your title that is also in the array. Line 34 puts it all back together, this is what you see in your permalink after you save or publish your blog post. Line 36 is the seo_slugs function giving your brand new slug back to WordPress.
And there you have it, the entire SEO Slugs plugin.
Give it try, see what you think.
UPDATE: Don’t know why I didn’t think of this before.
“Why all this toil and trouble?”
That’s a pretty good question.
In part, I’m showing you exactly what I do when I teach myself. I just go through the code one line at a time, learn what each line does, then (the hard part) figure out why that line is necessary.
Understanding source code requires an investment of time and mental energy. While I eat this stuff two or three meals per day, it’s not quite to some people’s taste, and others are downright allergic to the very notion.
But there are rewards.
One of which is overcoming all fear of WordPress coding. Well, at least most fear. There is some scary sh*t in the WordPress core, but you never need look at that if you just stick to WordPress plugins.
Knowledge builds on itself incrementally. Learning a half dozen of the most common functions you find in plugins goes a long way to stomping that learning curve flat. This is usually irrelevant, I admit, except when it’s Zero Dark Thirty and your blog is down. And you don’t know why. Then knowing a little WordPress seems pretty smart.
In any case, between this article and Blog Post Engineering, you have a grip on post slugs. Provided you have a grip on Blog Post Engineering… 
Lagniappe
July 17, 2010, and I’ve put a full week into the next release of Blog Post Engineering. Julie Angelos just pinged Top 10 Reasons WordPress is the future of the internet, with a CommentLuv link looking like this:ㄥ❀∨モ criticism ♥.
How could anyone resist that?
Now, I asserted that SEO Slugs removes fancy pants HTML entities, and it does. But you can still have such beasties in your post slug, just paste them in manually.
Here’s proof:

I have no idea what the effect on SEO is with such a spiffy little post slug. Neither do I care! Once in a while, just have some fun tweaking the rules.







That was a beautifully simple way to do it… Obviously I’ve not coded in WP itself, but I’ve seen myself coding in C++ (or *shudder* Java) with a different set of logic and it taking far longer.
Admittedly it wasn’t for post slugs, but you get the idea. ;) I love Tech Tuesdays.
.-= Heather´s last blog ..The Mayans: Intruder! =-.
I’ll do more of these, time permitting. I have several in queue.
.-= Dave Doolin´s last blog ..Secrets of the Tomorrow Blog, Today =-.
Cool, always up for some plugin tech. :)
.-= Heather´s last blog ..The Mayans: Intruder! =-.
Ooo… I’m loving Tech Tuesdays. I feel better that I’m not the only one digging into the code of plugin I use and see if the developer actually knows the stuff or did someone just got lucky and make it work…
And I like’em slugs too. Good job on tearing this one open. Nice and elegant code in this plugin, as the best of them do.
p.s. loved that cleverly hidden BPE discount thingie… I’ll leave it for someone else because I have the beauty already.
.-= Antti Kokkonen´s last blog ..You are losing money with your slow blog! (and how to fix it) =-.
Insightful my friend. Incidentally, I hadn’t heard of this plugin, but then again, I’m fairly new to WordPress.
Love the way you broke the code down. As a coder myself, it was a lovely read helpful too. I’m going to check it out now.
.-= Mo “Mad Dog” Stoneskin´s last undefined ..Response cached until Tue 18 @ 14:24 GMT (Refreshes in 54 Minutes) =-.
Nice Dave! :)
As you already know, I have no experience with coding php or such, only html and some css…
Now I learnt something from this post, explained nice and simple… thanks.
I must learn more and I will.
.-= rob sellen´s last blog ..Are we bloggers missing readers? =-.
Tell ya man, even digging a little ways into some PHP will sharpen your HTML and CSS a lot. It’s almost worth it for that alone.
Did you read my sushi article? Here: http://website-in-a-weekend.net/website-design/wordpress-dynamic-content-generation/
.-= Dave Doolin´s last blog ..Persistence – the critical trait for success, in any endeavor =-.
Yeah I can see exactly what you mean there Dave, I already notice how similar yet different it all all is, I mean opening tags, closing tags etc are still important on either and it’s not hard to know what the tags are when you already see that kind of thing in html.
Hooks and all that are interesting.
.-= rob sellen´s last blog ..Work to live or live to work =-.
I just have to ask this. Can I use the plugin without messing with the code? I really do have other things to do.
.-= Ralph´s last blog ..Wake up and smell the – Iris =-.
Yep. Just install it like any other plugin.
Make sure to check that you like the post slug though. It does a good job, but not always a great job.
I can still edit the slug?
.-= Ralph´s last blog ..Wake up and smell the – Iris =-.
Screencast. Enjoy.
That video made it easier to understand:) Anyway, was looking for a plugin like this and was not sure about some of them because they were old and did not know if they were compatible to newer versions of WP. I’ll definitely install this and see how it works. Looks good
.-= DiTesco´s last blog ..To Make Money Online, You Must Complete The Cycle =-.
Ooo, Never knew about this plugin… Just trying to start SEO side of development as well. Will give this a try, and always great content =)
.-= Brian Donaldson´s last blog ..Alternative Model Violet Raven =-.
Doolin, you are a serious badass. This post was a fun and interesting read. I am digging techtues even if I don’t understand a lot of it. I think at heart I am a bit of a programmer but have never dug in to learn much. Just some basic (BASIC) html that I learn from reading 50 or so pages in an HTML For Dummies book in 2000.
Anyway, killer post, cleverly written. This is why you are a WordPress Blogging Genius. Suck up done.
.-= Carlos Velez´s last blog ..The Nastiest, Stickiest, Most Controversial Question About the Law of Attraction =-.
Extremely thorough review, especially with going over the code bit by bit. Nice writeup, I am going to update my article and link back to this one.
Justin Germino´s last post ..BitLy Does Not Track Links with Hashtags in Tweet
Justin, thanks, I appreciate the link. I love writing these kinds of articles, but they really are costly in time, so I can’t do it very much.
Dave Doolin´s last post ..Backlink Kickstart – Don’t wait- create your own
That’s not a plug-in, at least not for a beginner who thinks code is half a word (codewords…political-speak, don’t ya know).
A plug in for us has a button that says “press to install”, like on the WP plugin page (post?).
Write for the stupid (see the other suggestion that directed you here), and instruct for the stupid, like me who needs a “press to install” button…
Bob
(…code indeed…sounds like a damn political operative…)
Bob Hayles´s last post ..Obama Understands Subservience
Not a chance:
* http://website-in-a-weekend.net/blogging-success/dumb-smarten/
* http://website-in-a-weekend.net/extending-wordpress/teach-css-wordpress/
Let me know what isn’t clear and I’ll make it more clear.
Dave Doolin´s last post ..Blog Post Engineering 072 ready to roll
Dave,
Did SEO plugin withstand the 3.1 upgrade? Kinda skittish with plugins, but if it’s working for you and this article concurs with 3.1 upgrade, that’s good enough for me to try this. Sure make it easier on me and who knows, the plugin might teach me a thing or two about writing good slugs
Yehudit Steinberg´s last post ..Jewish Father and Groom Toast – To Life! L’chaim
It should be fine. The way it’s written, it uses very basic WordPress and PHP functions. There would have to be some pretty major changes in both PHP and WordPress to break this plugin!
Dave Doolin´s last post ..Website Hosting for Your Benefit not mine
Hey,
Just gotta tell you that your book “SEO Blog Post Engineering” is so rich with information. I love the step-by-step approach along with the book being a reference guide. I keep it right by my desk.
Your content is rich with little goodies, It is well worth the money. I highly recommend the book and your website in a weekend ‘live’ in downtown Oakland. [ a really cool up and coming place. Really good Food!] Can’t wait for the next one! Is that in July 2011?
I learned so much spending the three day intensive with you and Anca of Techliminal, Oakland CA. You made it so much fun.
Anyone serious about making an online presence successful needs this information. There is a lot to learn, but if you are detailed oriented and have good guides to help you along your journey, it can be very rewarding.
Yehudit Steinberg´s last post ..Jewish Father and Groom Toast – To Life! L’chaim
Thank you! Even the though the basics seems very simple (write. publish.) I’m convinced it’s the mass of all those little details compounding over time which build long -lasting success.
Dave Doolin´s last post ..Website Hosting for Your Benefit not mine