stand·first /ˈstan(d)ˌfərst/

noun

  1. a brief introductory summary of an article in a newspaper or on a website, typically appearing immediately after the headline and typographically distinct from the rest of the article.

In the WordPress space, we typically think of the excerpt and the intro or lede text for an article, and the ecosystem uses this for a variety of things – SEO, card intros, etc., but WordPress natively decides that if you do not add an excerpt, you must want a number of characters in the body to serve as your excerpt. This is acceptable if the content is text, but using a plugin can introduce unexpected content into the flow, and it can play havoc with your search results. After doing some research, I found that the print industry — the basic model of the modern web — already had a feature called the standfirst.

Why use a standfirst

Implementing a custom field called the standfirst can provide additional benefits. First, it doesn’t take away from the excerpt, so you can continue to use it for the recommended 160-character SEO description. Second, it provides a means to include longer introductory text, either in a card or at the top of a story. Third, it can easily support HTML; fourth, it can enhance search results with more detailed information without compromising the overall results. The latter assumes you are building a custom search template.

This can also be really helpful if you do not want to enable the excerpt field in a custom post type. being able to limit the user to a specified number of characters, rather than the free-for-all approach of WordPress. Most SEO tools will let you map a custom field to the SEO description. I think a good scenario would be to have an SEO standfirst, a standard standfirst, and a long standfirst (maybe using a WYSIWYG editor instead of a text area).

My implementation

I decided to find a way to have my excerpt auto-populate the standfirst by default. If I need a true standfirst, I can add my own or modify the default input. Using Meta Box, I created a custom field called … wait for it … wait for it … standfirst.

<?php 
/**
 * Seed Meta Box field "standfirst" from the *manual* Excerpt (post_excerpt) one time.
 * - Default scope: only the 'post' post type
 * - Extendable: add post types via the filter below
 * - Never overwrites once the meta key exists (even if emptied later)
 */
add_action( 'save_post', function ( $post_id, $post, $update ) {

	// Bail on autosaves/revisions.
	if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
		return;
	}

	// Ensure we have a post object.
	if ( ! $post instanceof WP_Post ) {
		$post = get_post( $post_id );
		if ( ! $post ) return;
	}

	// Permissions.
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return;
	}

	// Default: only seed for standard Posts.
	$post_types = apply_filters( 'fwe_standfirst_seed_post_types', [ 'post' ] );

	if ( ! in_array( $post->post_type, $post_types, true ) ) {
		return;
	}

	$meta_key = 'standfirst'; // Meta Box field ID

	// Only seed once: if the meta key has ever existed, never overwrite.
	if ( metadata_exists( 'post', $post_id, $meta_key ) ) {
		return;
	}

	// Manual excerpt only (NOT auto-generated).
	$manual_excerpt = trim( (string) get_post_field( 'post_excerpt', $post_id ) );

	if ( $manual_excerpt === '' ) {
		return; // Leave standfirst unset/empty if no manual excerpt.
	}

	update_post_meta( $post_id, $meta_key, $manual_excerpt );

}, 20, 3 );
//Extend to othe post types
add_filter( 'fwe_standfirst_seed_post_types', function ( $types ) {
	$types[] = 'page';
	$types[] = 'events';
	return array_values( array_unique( $types ) );
} );
PHP

Now I can ensure that my search results include the content I want, that SEO is not affected, and that my single post template can include the standfirst dynamically.