Like the blog? Get the book »

DIY Alternative to WordPress SEO Plugins

DIY Alternative to WordPress SEO Plugins

Most SEO plugins have way too many bells and whistles for my simple needs, so I wrote a little snippet that’s meant as a drop-in, DIY replacement for the big WordPress SEO plugins. If you want a lot of features and options, then try Yoast’s awesome SEO plugin or the great All in One SEO; otherwise, if you just want something simple that works, check out Basic WP SEO — a simple slab of code that you add to your functions.php file and done.

What does this code do?

Simple. It optimizes your WordPress pages for search engines by including the following meta data in the <head> section:

  • Meta description – uses custom meta if exists, else uses the first 155 words of content
  • Meta keywords – uses custom meta if exists, else generates from tags and categories
  • Meta Robots – includes meta robots index/follow or noindex/follow depending on page
  • SEO title – uses custom meta if exists, else generates an optimized unique title

These are some useful, beneficial things to include in your web pages, which is why SEO plugins are so popular. The problem is that most SEO plugins are just way too overwrought and heavy-handed, especially for DIY folk who implement stuff like .htaccess, robots.txt, sitemaps, and Google Analytics via their own optimized methods.

Trying to roll it all up into a single plugin just wasn’t working for me, but I needed something solid for my own sites’s SEO and now am using the following Basic WP SEO snippet, which I’ll eventually turn into a plugin of its own:

/* Basic WP SEO
		1. add this code to functions.php
		2. replace the $default_keywords with your own
		3. add <?php echo basic_wp_seo(); ?> to header.php
		4. test well and fine tune as needed

	Optional: add custom description, keywords, and/or title
	to any post or page using these custom field keys:


	To migrate from any SEO plugin, replace its custom field 
	keys with those listed above. More information:

function basic_wp_seo() {
	global $page, $paged, $post;
	$default_keywords = 'wordpress, plugins, themes, design, dev, development, security, htaccess, apache, php, sql, html, css, jquery, javascript, tutorials'; // customize
	$output = '';

	// description
	$seo_desc = get_post_meta($post->ID, 'mm_seo_desc', true);
	$description = get_bloginfo('description', 'display');
	$pagedata = get_post($post->ID);
	if (is_singular()) {
		if (!empty($seo_desc)) {
			$content = $seo_desc;
		} else if (!empty($pagedata)) {
			$content = apply_filters('the_excerpt_rss', $pagedata->post_content);
			$content = substr(trim(strip_tags($content)), 0, 155);
			$content = preg_replace('#\n#', ' ', $content);
			$content = preg_replace('#\s{2,}#', ' ', $content);
			$content = trim($content);
	} else {
		$content = $description;	
	$output .= '<meta name="description" content="' . esc_attr($content) . '">' . "\n";

	// keywords
	$keys = get_post_meta($post->ID, 'mm_seo_keywords', true);
	$cats = get_the_category();
	$tags = get_the_tags();
	if (empty($keys)) {
		if (!empty($cats)) foreach($cats as $cat) $keys .= $cat->name . ', ';
		if (!empty($tags)) foreach($tags as $tag) $keys .= $tag->name . ', ';
		$keys .= $default_keywords;
	$output .= "\t\t" . '<meta name="keywords" content="' . esc_attr($keys) . '">' . "\n";

	// robots
	if (is_category() || is_tag()) {
		$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
		if ($paged > 1) {
			$output .=  "\t\t" . '<meta name="robots" content="noindex,follow">' . "\n";
		} else {
			$output .=  "\t\t" . '<meta name="robots" content="index,follow">' . "\n";
	} else if (is_home() || is_singular()) {
		$output .=  "\t\t" . '<meta name="robots" content="index,follow">' . "\n";
	} else {
		$output .= "\t\t" . '<meta name="robots" content="noindex,follow">' . "\n";

	// title
	$title_custom = get_post_meta($post->ID, 'mm_seo_title', true);
	$url = ltrim(esc_url($_SERVER['REQUEST_URI']), '/');
	$name = get_bloginfo('name', 'display');
	$title = trim(wp_title('', false));
	$cat = single_cat_title('', false);
	$tag = single_tag_title('', false);
	$search = get_search_query();

	if (!empty($title_custom)) $title = $title_custom;
	if ($paged >= 2 || $page >= 2) $page_number = ' | ' . sprintf('Page %s', max($paged, $page));
	else $page_number = '';

	if (is_home() || is_front_page()) $seo_title = $name . ' | ' . $description;
	elseif (is_singular())            $seo_title = $title . ' | ' . $name;
	elseif (is_tag())                 $seo_title = 'Tag Archive: ' . $tag . ' | ' . $name;
	elseif (is_category())            $seo_title = 'Category Archive: ' . $cat . ' | ' . $name;
	elseif (is_archive())             $seo_title = 'Archive: ' . $title . ' | ' . $name;
	elseif (is_search())              $seo_title = 'Search: ' . $search . ' | ' . $name;
	elseif (is_404())                 $seo_title = '404 - Not Found: ' . $url . ' | ' . $name;
	else                              $seo_title = $name . ' | ' . $description;

	$output .= "\t\t" . '<title>' . esc_attr($seo_title . $page_number) . '</title>' . "\n";

	return $output;

So that’s it, just enter your default keywords and then call the function by including this tag in the <head> section of your pages (e.g., header.php):

<?php echo basic_wp_seo(); ?>

Note that this code is a replacement/alternative for existing methods, so it doesn’t overwrite or hook into anything — call it wherever and customize as needed. This also means that you’ll want to remove any existing <title> or <meta> tags that may already exist in your theme’s header.php file.

Once the Basic WP SEO script and header tag are uploaded to the server, visit each of the different types of pages (e.g., single, index, archive, search, 404, et al) and view the source code to verify proper functionality. In other words, I’ve tested this script thoroughly on my own sites (e.g., you can see this code in action at Perishable Press and here at, but your mileage may vary so test well and fine-tune as needed.


With a simple script, the features are fewer, but again that’s the whole point. Here are some “micro-features” of Basic WP SEO:

  • One script, plug-n-play functionality with minimal configuration
  • Optimized title tags based on Perfect WordPress Title Tags
  • Makes it easy to migrate and use data from most any SEO plugin
  • Generates SEO-optimized meta robots tags for all page views
  • Outputs clean markup with no funky HTML comments, et al

Again, the main purpose of this script is to provide a simple alternative to the “all-purpose” WP SEO plugins currently available. With Yoast and All in One for example, functionality goes far beyond optimized meta/robots and title tags; you also get sitemaps, navigation links, Google Analytics, and the whole nine yards. So the main feature of the Basic WP SEO script is that it doesn’t try to do it all, instead it focuses on the basics and lets you go from there.

Migrating from AiOSEO, Yoast SEO, or similar

Support for existing/custom meta data is baked right in, so you can continue adding custom keywords, titles, and descriptions for individual posts and pages via custom fields. Then, to utilize any existing meta data from other SEO plugins, you basically have two options: change the script or rename the meta fields in the database. For example, at Perishable Press, I was using AiOSEO before trying WP SEO, then tried Yoast SEO, so my WP database contained lots of weird looking custom meta fields like this:


Apparently Yoast SEO prepends its prefix to any existing SEO fields when activated, so who knows what names you’ll actually see in your database, but the meta data should look similar. In any case, once you’ve got the names of the meta fields, there are two ways of migrating from the SEO plugin to the Basic WP SEO script:

  • Edit the mm_seo_desc, mm_seo_keywords, mm_seo_title in the Basic WP SEO script to match the existing field values.
  • OR if you’re sure that you won’t be returning to the SEO plugin, simply rename the meta fields in the database (explained below)

Of these choices, I went ahead and just renamed the db fields using the following SQL commands:

UPDATE `wp_postmeta` SET `meta_key` = 'mm_seo_keywords' WHERE `meta_key` = '_yoast_wpseo_metakeywords'
UPDATE `wp_postmeta` SET `meta_key` = 'mm_seo_title' WHERE `meta_key` = '_yoast_wpseo_title'
UPDATE `wp_postmeta` SET `meta_key` = 'mm_seo_desc' WHERE `meta_key` = '_yoast_wpseo_metadesc'

Some notes about these queries:

  • BACKUP your database before making any changes
  • The underscore means that the custom field is hidden; omitting it means the custom field will be available for use and customization via Post/Page editor.
  • You’ll want to replace the _yoast_wpseo_metakeywords and other names with the actual names used in your database.
  • Also, wp_postmeta is the default table name, so if you’re using custom database prefix, you’ll need to add it (for example, you’ll need to change wp_postmeta to whatever_wp_postmeta if your custom db prefix is “whatever_”).

Once the meta fields have been renamed, they will be used by the Basic WP SEO script if available; or if not, then you can either add them manually (via custom fields), or else the script will automatically generate unique descriptions, keywords, titles, and robots tags for your posts and pages.

Bon Voyage

I hope this technique helps others who find themselves wanting a simpler SEO solution. I’m currently using this exact script at four of my sites and it’s been doing great, so I thought I would share with you fine folks in the WP community.

On-topic ideas and suggestions welcome! :)

28 responses

  1. Barış Ünver

    I have similar functions like this, providing my blog Beyn with basic SEO stuff. You should submit the code as a Github Gist :)

  2. How i can set the pages or better only the site “impress” to no-index, no-follow? I will my private impress-data not in the index.

  3. What if you run Multisite?

  4. perfect and very simple function)
    I use this thing to the next project

  5. Great little script, pity though that it doesn’t come properly internationalised, so it can only be used on a one-language website only.

  6. Thanks Jeff, I like the simplicity of it. I’m currently using Yoast on my blogs but you’re right about it being all over the place. I don’t use half that stuff.

  7. Hmmm… I like every inch of Yoast though.

    Anyway, thanks for sharing your post. Glad that someone took their time to share these scripts.


  8. The end of Summer has come!

  9. Thanks for sharing this! When Yoast stopped working on Pages for me I was happy to find your simple alternative. I’m looking forward to the plugin!

  10. thank you for this useful codes,it’s really simple and handy.
    but the function get_page() was deprecated by get_post(), maybe you could update the post if you see this.

  11. Great post, especially if author meta and google analytics script were included yourself, this would be a great solution / alternative to some of the seo plugins.

  12. so how do you know if its working?

  13. okay sorry I just saw how in the post above I read to fast first time thru..
    you can delete these 2 comments

  14. wow slick tests out super great..

    [Once the Basic WP SEO script and header tag are uploaded to the server, visit each of the different types of pages (e.g., single, index, archive, search, 404, et al) and view the source code to verify proper functionality]

  15. The message that the Summer’s gone was deleted?! It was just a reminder about your plans to release a new version of Digging into WordPress by the end of Summer. Look forward to seeing a sleeker, more streamlined and better focused, than ever before, version of the book. :)

    • Ah my mistake, it looked like spam (sorry).. but yes the next version of the book is now underway, along with a revamp of the site’s design :)

      • Don’t apologize. It was a useless comment, the kind that pollutes the inboxes of all of us who subscribe.

  16. Meta keywords? It’s not 1990 anymore!

  17. I’m not quite sure whether the code is working and more efficient.Thanks for sharing the script.

  18. This is a sweet little script! Thanks! Re: meta keywords, Yoast does not recommend using these, but does include them in his plugin. Even if you don’t use his plugin, reading his Definitive Guide is illuminating.

  19. Yes, I agree. Sometimes you don’t need to have all of the bells and whistles that some plugins include. It’s not a bad thing to have access to them. It’s more a case that is can often over complicate things and unless people are more SEO savvy they wouldn’t necessarily understand what it all means.

  20. Thanks for your code
    I’m gonna try it right now even if a little bit long

  21. Thanks for sharing the code, I really like how simple and powerful it is, will try today and let you know the results! Cheers!

  22. will this work with WooCommerce

  23. I have the same questions as Sean…Thanks for checking it out!

  24. Hey,

    Thanks for sharing. Very interesting and will definitely have a lookat this SEO plugin.

    Thanks again.


Comments are closed for this post. Contact us with any critical information.
© 2009–2024 Digging Into WordPress Powered by WordPress Monzilla Media shapeSpace