Seo

SEO meta tags without plugin: title, description, robots, Open Graph

There are many plugins for SEO, but almost all of them have the main task – to create SEO meta tags (metadata) for the page: title, description, robots, Open Graph. Sometimes it makes sense not to connect such plugins, but use your small code – it’s easier to manage and solve non-standard tasks.

If you do not understand PHP, then I highly recommend using SEO plugins – it’s much more convenient! However, sometimes plug-ins are more convenient for those who know PHP, I will not always use this code, and I do not disdain plugins like Yoast SEO.

Output Code title, description, robots, Open Graph, Twitter

The basic task of SEO plugins is to enable you to create four meta posts for the page: title, description, robots, and keywords. And also the creation of additional Open Graph data.

The code that implements all this (see comments in the code):

// remove the standard output title 
remove_action (  'wp_head' ,  '_wp_render_title_tag' ,  1  ) ;

// call all functions in the HEAD page 
add_action (  'wp_head' ,  'kama_render_seo_tags' ,  1  ) ; 
function kama_render_seo_tags ( ) { 
	// remove_theme_support ('title-tag'); // not necessary

	echo '<title>'. kama_meta_title(' » ') .'</title>'."\n\n";

	echo kama_meta_description ( 'Text for main' ) ; 
	echo kama_meta_keywords ( 'keys, for, main' ) ; 
	echo kama_meta_robots ( ) ;

	echo kama_og_meta ( ) ;  // Open Graph, twitter data 
}

/**
 * Open Graph, twitter data in <head>.
 * documentation: http://ogp.me/
 *
 * @version 5
 * / 
function kama_og_meta ( ) {

	$obj = get_queried_object();

	// only for records or terms 
	if (  isset ( $ obj -> post_type )  ) 
		$ post  =  $ obj ; 
	elseif (  isset ( $ obj -> term_id )  ) 
		$ term  =  $ obj ;

	$is_post_page = isset($post);
	$is_term_page = isset($term);

	$title = kama_meta_title( '–' );
	$desc  = preg_replace( '/^.+content="([^"]*)".*$/s', '$1', kama_meta_description() );

	// Open Graph
	$els = array();
	$els['og:locale']      = '<meta property="og:locale" content="'. get_locale() .'" />';
	$els['og:site_name']   = '<meta property="og:site_name" content="'. esc_attr( get_bloginfo('name') ) .'" />';
	$els['og:title']       = '<meta property="og:title" content="'. esc_attr( $title ) .'" />';
	$els['og:description'] = '<meta property="og:description" content="'. esc_attr( $desc ) .'" />';
	$els['og:type']        = '<meta property="og:type" content="'.( is_singular() ? 'article' : 'object' ).'" />';

	if( $is_post_page ) $pageurl = get_permalink( $post );
	if( $is_term_page ) $pageurl = get_term_link( $term );
	if( isset($pageurl) )
		$els['og:url'] = '<meta property="og:url" content="'. esc_attr( $pageurl ) .'" />';

	if( apply_filters( 'kama_og_meta_show_article_section', true ) ){
		if( is_singular() && $post_taxname =  get_object_taxonomies($post->post_type) ){
			$post_terms = get_the_terms( $post, reset($post_taxname) );
			if( $post_terms && $post_term = array_shift($post_terms) )
				$els['article:section'] = '<meta property="article:section" content="'. esc_attr( $post_term->name ) .'" />';
		}
	}

	// image
	$thumb_id = 0;
	if    ( $is_post_page ) $thumb_id = get_post_thumbnail_id( $post );
	elseif( $is_term_page ) $thumb_id = get_term_meta( $term->term_id, '_thumbnail_id', 1 );
	$thumb_id = apply_filters( 'kama_og_meta_thumb_id', $thumb_id );

	if( $thumb_id ){
		list( $image_url, $img_width, $img_height ) = image_downsize( $thumb_id, 'full' );

		// Open Graph image
		$els['og:image']        = '<meta property="og:image" content="'. esc_url($image_url) .'" />';
		$els['og:image:width']  = '<meta property="og:image:width" content="'. (int) $img_width .'" />';
		$els['og:image:height'] = '<meta property="og:image:height" content="'. (int) $img_height .'" />';
	}

	// twitter
	$els['twitter:card']         = '<meta name="twitter:card" content="summary" />';
	$els['twitter:description']  = '<meta name="twitter:description" content="'. esc_attr( $desc ) .'" />';
	$els['twitter:title']        = '<meta name="twitter:title" content="'. esc_attr( $title ) .'" />';
	$ them))$ image_url(isset(if  
		['twitter:image'] = '<meta name="twitter:image" content="'. esc_url($image_url) .'" />';

	$ els  = apply_filters (  'kama_og_meta_elements' ,  $ els  ) ;

	return "\n\n". implode("\n", $els ) ."\n\n";
}

/**
 * Displays the title of the page <title>
 *
 * For labels and categories indicated in the settings, in the description: [title = Title].
 * For records, if you want the page title to be different from the title of the entry,
 * Create an arbitrary title field and enter an arbitrary title there.
 *
 * @version 4.8
 *
 * @param string $ sep separator
 * @param true | false $ add_blog_name add the name of the blog to the end of the header for the archives.
 */
function kama_meta_title( $sep = '»', $add_blog_name = true ){
	static $cache; if( $cache ) return $cache;

	global $post;

	$ l10n  = apply_filters (  'kama_meta_title_l10n' ,  array ( 
		'404'      = >  'Error 404: no such page exists' , 
		' search '   = >  ' Search results for:% s' , 
		'compage'  = >  'Comments% s ' , 
		' author '   = >  ' Author's articles:% s' , 
		'archive'  = >  'Archive for' , 
		'paged'    = >  '(page% d)' , 
	)  ) ;

	$parts = array(
		'prev'  => '',
		'title' => '',
		'after' => '',
		'paged' => '',
	);
	$title = & $parts['title']; // simplify
	$after = & $parts['after']; // simplify

	if(0){}
	// 404
	elseif ( is_404() ){
		$title = $l10n['404'];
	}
	// Search
	elseif ( is_search() ){
		$title = sprintf( $l10n['search'], get_query_var('s') );
	}
	// home
	elseif( is_front_page() ){
		if( is_page() && $title = get_post_meta( $post->ID, 'title', 1 ) ){
			// $title determined
		} else {
			$title = get_bloginfo('name');
			$after = get_bloginfo('description');
		}
	}
	// separate page
	elseif( is_singular() || ( is_home() && ! is_front_page() ) || ( is_page() && ! is_front_page() ) ){
		$title = get_post_meta( $post->ID, 'title', 1 ); // the specified title of the entry in priority

		if( ! $title ) $title = apply_filters( 'kama_meta_title_singular', '', $post );
		if( ! $title ) $title = single_post_title( '', 0 );

		if( $cpage = get_query_var('cpage') )
			$parts['prev'] = sprintf( $l10n['compage'], $cpage );
	}
	// post type archive
	elseif ( is_post_type_archive() ){
		$title = post_type_archive_title('', 0 );
		$after = 'blog_name';
	}
	// taxonomy
	elseif( is_category() || is_tag() || is_tax() ){
		$term = get_queried_object();

		$title = get_term_meta( $term->term_id, 'title', 1 );

		if( ! $title ){
			$title = single_term_title('', 0 );

			if( is_tax() )
				$parts['prev'] = get_taxonomy($term->taxonomy)->labels->name;
		}

		$after = 'blog_name';
	}
	// author's archive
	elseif ( is_author() ){
		$title = sprintf( $l10n['author'], get_queried_object()->display_name );
		$after = 'blog_name';
	}
	// date archive
	elseif ( ( get_locale() === 'en_EN' ) && ( is_day() || | is_month ( )  | | | is_year ( )  )  ) { 
		$ rus_month   =  array ( '' ,  'January' ,  'February' ,  'March' ,  'April' ,  'May' ,  'June' ,  'July' ,  'August' ,  'September' ,  'October' ,  'November' ,  'December' ) ; 
		$ rus_month2  =  array ( '' ,  February ,  March ,  April ,  May ,  June ,  July ,  August ,  September ,  October ,  November ,  December ) ; 
		$ year        = get_query_var ( 'year' ) ; 
		$ monthnum    = get_query_var ( 'monthnum' ) ; 
		$ day         = get_query_var ( 'day' ) ;

		if( is_year() )      $dat = "$year year";
		elseif( is_month() ) $dat = "$month[$monthnum] $year of the year";
		elseif( is_day() )   $dat = "$day $month2[$monthnum] $year of the year";

		$title = sprintf( $l10n['archive'], $dat );
		$after = 'blog_name';
	}
	// other archives
	else {
		$title = get_the_archive_title();
		$after = 'blog_name';
	}

	// page numbers for pagination and division of the record 
	$ pagenum  = get_query_var ( 'paged' )  ? : get_query_var ( 'page' ) ; 
	if (  $ pagenum  ) 
		$ parts [ 'paged' ]  = sprintf (  $ l10n [ 'paged' ] ,  $ pagenum  ) ;

	// allows you to filter the title as you like. The header itself 
	// $ parts contains an array with the elements: prev - text before, title - header, after - text after 
	$ parts  = apply_filters_ref_array (  'kama_meta_title_parts' ,  array ( $ parts ,  $ l10n )  ) ;

	if( $after == 'blog_name' )
		$after = $add_blog_name ? get_bloginfo('name') : '';

	// add pagination to title
	if( $parts['paged'] ){
		$parts['title'] .=  " {$parts['paged']}";
		unset( $parts['paged'] );
	}

	$title = implode( ' '. trim($sep) .' ', array_filter($parts) );

	//$title = apply_filters( 'kama_meta_title', $title );

	$title = wptexturize( $title );
	$title = esc_html( $title );

	return $cache = $title;
}

/**
 * Displays the description meta tag.
 *
 * For taxonomy elements: a metapole description or in the description of such a shtocode [description = description text]
 * The posts are first checked, the meta description, or quote, or the initial part of the content.
 * The quotation or content is truncated to the specified in $ maxchar characters.
 *
 * @param $ home_description indicating a description for the main page of the site.
 * @param $ maxchar Maximum description length (in characters).
 *
 * @version 0.15
 */
function kama_meta_description( $home_description = '', $maxchar = 160 ){
	static $cache; if( $cache ) return $cache;

	global $post;

	$cut = true;
	$desc = '';

	// front 
	if ( is_front_page ( )  ) { 
		// when the main page is set 
		if ( is_page ( )  & &  $ desc  = get_post_meta ( $ post -> ID ,  'description' ,  true  )   ) { 
			$ cut  =  false ; 
		}

		if( ! $desc )
			$desc = $home_description ?: get_bloginfo( 'description', 'display' );
	}
	// singular
	elseif( is_singular() ){
		if( $desc = get_post_meta($post->ID, 'description', true ) )
			$cut = false;

		if( ! $desc ) $desc = $post->post_excerpt ?: $post->post_content;

		$desc = trim( strip_tags( $desc ) );
	}
	// term
	elseif( is_category() || is_tag() || is_tax() ){
		$term = get_queried_object();

		$desc = get_term_meta( $term->term_id, 'meta_description', true );
		$cut = false;

		if( ! $desc && $term->description ){
			$desc = strip_tags( $term->description );
			$cut = true;
		}
	}

	if( $desc ){
		$origin_out = $desc;
		$desc = str_replace( array("\n", "\r"), ' ', $desc );
		$desc = preg_replace( '~\[[^\]]+\](?!\()~', '', $desc ); // remove shortcodes. Leaving the markdown [foo](URL)

		$desc = apply_filters( 'kama_meta_description_pre_cut', $desc );

		if (  $ cut  ) { 
			$ char  = mb_strlen (  $ desc  ) ; 
			if (  $ char  >  $ maxchar  ) { 
				$ desc      = mb_substr (  $ desc ,  0 ,  $ maxchar  ) ; 
				$ words     = explode ( '' ,  $ desc  ) ; 
				$ maxwords  = count ( $ words )  -  1 ;  // remove the last word, it is in 90% of cases incomplete 
				$ desc     = join(' ', array_slice($words, 0, $maxwords)).' ...';
			}
		}

		$desc = apply_filters( 'kama_meta_description', $desc, $origin_out, $cut, $maxchar );
		if( $desc )
			return $cache = '<meta name="description" content="'. esc_attr( trim($desc) ) .'" />'."\n";
	}

}

/**
 * Generates a meta tag of keywords for the head of a site
 *
 * To specify your keywords for the record, create an arbitrary keywords field and enter the necessary keywords into the values.
 * For posts (post), keywords are generated from tags and category names, unless an arbitrary field of keywords is specified.
 *
 * For labels, categories and arbitrary taxonomies, keywords are specified in the description, in the shotcode: [keywords = word1, word2, word3]
 *
 * @ $ home_keywords: For the main, the keywords are specified in the first parameter: kama_meta_keywords ('word1, word2, word3');
 * @ $ def_keywords: pass-through keywords - specify and they will be added to the rest on all pages
 *
 * version 0.7
 */
function kama_meta_keywords( $home_keywords = '', $def_keywords = '' ){
	global $wp_query, $post;
	$out = '';

	if ( is_front_page() ){
		$out = $home_keywords;
	}
	elseif( is_singular() ){
		$out = get_post_meta( $post->ID, 'keywords', true );

		// for posts we specify the keys of the label and the category if the keys are not specified in an arbitrary field 
		if (  !  $ out  & &  $ post -> post_type ==  'post'  ) { 
			$ res  = wp_get_object_terms (  $ post -> ID ,  array ( ' post_tag ' ,  ' category ' ) ,  array ( ' orderby '  = >  ' none ' )  ) ;  // get categories and tags

			if( $res && ! is_wp_error($res) ) foreach( $res as $tag ) $out .= ", $tag->name";

			$out = ltrim( $out, ', ' );
		}
	}
	elseif ( is_category() || is_tag() || is_tax() ){
		$term = get_queried_object();

		// wp 4.4
		if( function_exists('get_term_meta') ){
			$out = get_term_meta( $term->term_id, "keywords", true );
		}
		else{
			preg_match( '!\[keywords=([^\]]+)\]!iU', $term->description, $match );
			$out = isset($match[1]) ? $match[1] : '';
		}

	}

	if( $out && $def_keywords )
		$out = $out .', '. $def_keywords;

	if( $out )
		return "<meta name=\"keywords\" content=\"$out\" />\n";
}

/**
 * Metateg robots
 *
 * To specify your robots meta tag attributes, create an arbitrary field with a robots key
 * and the necessary value, for example: noindex, nofollow
 *
 * Specify the $ allow_types parameter to allow indexing of page types.
 *
 * @ $ allow_types What types of pages need to be indexed (separated by commas):
 *                cpage, is_category, is_tag, is_tax, is_author, is_year, is_month,
 *                is_attachment, is_day, is_search, is_feed, is_post_type_archive, is_paged
 * (you can use any conditional tags as a string)
 * cpage - comment pages
 * @ $ robots How to close indexing: noindex, nofollow
 *
 * version 0.6
 */
function kama_meta_robots( $allow_types = null, $robots = 'noindex,nofollow' ){
	global $post;

	if( null === $allow_types ) $allow_types = 'cpage, is_category, is_attachment, is_tag, is_tax, is_paged, is_post_type_archive';

	if( ( is_home() || is_front_page() ) && ! is_paged() ) return;

	if ( is_singular ( )  ) { 
		// if this is not an attachment or an attachment, but it is allowed 
		if (  ! is_attachment ( )  | |  false  ! = = strpos ( $ allow_types , 'is_attachment' )  ) { 
			$ robots  = get_post_meta (  $ post -> ID ,  'robots' ,  true  ) ; 
		} 
	} 
	else  { 
		$ types  = preg_split ( '~ [,] + ~', $allow_types );
		$types = array_filter( $types );

		foreach( $types as $type ){
			if( $type == 'cpage' && strpos($_SERVER['REQUEST_URI'], '/comment-page') ) $robots = false;
			elseif( function_exists($type) && $type() )                                $robots = false;
		}
	}

	$robots = apply_filters( 'kama_meta_robots_close', $robots );

	if( $robots )
		return "<meta name=\"robots\" content=\"$robots\" />\n";
}
Connectivity SEO plugin

I recommend copying the code into a separate PHP file, for example, seo.phpand connect it to a theme filefunctions.php

require_once 'seo.php';

That’s all, the code immediately starts working, you do not need to add anything else anywhere – everything works through hooks. The only thing is to make sure that header.phpthere is a function call in the theme file wp_head()and that there is no hardcoded tag <title>and other SEO tags out there.

Metafolia in the admin panel

The code above only displays the necessary SEO meta tags but does not add a meta-field for entries or taxonomy elements-they need to be created separately.

On the edit page of a record or term, you need to create a meta box with meta fields:

  • Title – an alternative SEO header will be used in the meta tags,<title> instead of the title of the entry.
  • Description – Description of the page. If it is not, it will take the text from the quote, if it is not, then a piece from the beginning of the content of the record.meta_description – this should be called the description metal pole for terms because the key descriptionfor taxonomy is busy.
  • Keywords – keywords meta tag. I do not know if he needs it or not at all in modern realities.
  • robots – the value specified here is displayed as is, for example noindex,nofollow
Fine-tune output

The code contains all the necessary hooks to completely or partially change the output of each meta pole.

One of the advantages of this code over plugins is the quick solution to a non-standard task. All this is done through hooks and here and in plugins, only to find the proper hook in the plugin usually takes more time. Also, you can rewrite part of the code for your specific task.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

    Leave a Reply

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