Get an excerpt for a post outside of the loop

The WordPress get_the_excerpt() function does not behave well outside of a loop.

This will do so nicely:

/**
 * Get the excerpt for a post for use outside of the loop.
 *
 * @param int|WP_Post $post ID or WP_Post object.
 * @param int         Optional excerpt length.
 * @return string Excerpt.
 */
function prefix_get_the_excerpt( $post, $excerpt_length = null ) {

	$excerpt = get_post_field( 'post_excerpt', $post );

	if ( '' === $excerpt ) {

		$content = get_post_field( 'post_content', $post );

		// An empty string will make wp_trim_excerpt do stuff we do not want.
		if ( '' !== $content ) {

			$excerpt = strip_shortcodes( $content );

			/** This filter is documented in wp-includes/post-template.php */
			$excerpt = apply_filters( 'the_content', $excerpt );
			$excerpt = str_replace( ']]>', ']]>', $excerpt );

			if ( ! $excerpt_length ) {
				/** This filter is documented in wp-includes/formatting.php */
				$excerpt_length = apply_filters( 'excerpt_length', 55 );
			}

			/** This filter is documented in wp-includes/formatting.php */
			$excerpt_more = apply_filters( 'excerpt_more', ' ' . '[…]' );

			$excerpt = wp_trim_words( $excerpt, $excerpt_length, $excerpt_more );
		}
	}

	return apply_filters( 'the_excerpt', $excerpt );
}

/**
 * The excerpt for a post for use outside of the loop.
 *
 * @param int|WP_Post $post ID or WP_Post object.
 * @param int         Optional excerpt length.
 */
function prefix_the_excerpt( $post, $excerpt_length = null ) {

	echo wp_kses_post( prefix_get_the_excerpt( $post, $excerpt_length ) );
}