DIY wordpress SEO

DIY wordpress SEO
September 21, 2016 Cameron James

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:


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.


Leave a reply

Your email address will not be published. Required fields are marked *