WordPress Embed と内部ブログカード

WordPress は標準の機能で、ブログや YouTube の動画、ツイート、音楽などの様々なコンテンツを、簡単にそして安全に埋め込むことができます。

一般的に 「Embed」といわれている機能です。ブログなどでは「ブログカード」などとも言われています。

oEmbed

埋め込みできるコンテンツのほとんどは、oEmbed によって提供されています。oEmbed とは埋め込み用のコンテンツを取得するためのプロトコルです。

はてなブログや YouTube、Twitter も、oEmbed プロバイダー(埋め込まれる側)に対応しているため、埋め込むことができるわけです。

WordPress 自体も oEmbed プロバイダーに対応(バージョン 4.4 以降)しているので、外部の WordPress サイトもサイト内でも埋め込むことができます。

コンテンツを埋め込むには、Embed ショートコードまたは、単に URL(独立した行)を記述するだけです。

内部ブログカード

便利な機能ではあるのですが、埋め込みに失敗して URL だけが表示されることがよくあります。なぜ、そうなるかはここでは置いておくとして、外部サイトが失敗するのは仕方がないとしても、サイト内の埋め込みが失敗するのは避けたいところです。その為に、ブログカードを表示するプラグインを使用するのもいいかもしれませんが、既存の記事を変更しないといけなかったりするので、ここでは手軽な方法として、記事の変更をすることなくサイト内の記事のみを対象に、独自のブログカード(以降「内部ブログカード」と表記)を表示する方法とします。

処理としては、Embed ショートコードで指定された URL が、サイト内の記事の場合のみ内部ブログカードを出力し、それ以外は標準の埋め込みコードとします。URL の記述も、内部的には Embed ショートコードに変換されているので対象となります。

方法はとっても簡単です。embed_oembed_html フィルタフックで埋め込みコードを変更することができるので、ここで URL がサイト内の記事の場合のみ、内部ブログカードへ変更します。

コードは下記の通りです。functions.php 等に追記してください。

/**
 * Generates excerpts for Blog Card from content.
 *
 * @param WP_Post $post Post object.
 * @return string The excerpt.
 */
function get_excerpt_for_blog_card( $post ) {
	$excerpt = trim( $post->post_excerpt );
	if ( ! $excerpt ) {
		$excerpt = apply_filters( 'the_content', strip_shortcodes( $post->post_content ) );
		$excerpt = str_replace( ']]>', ']]>', $excerpt );
	}
	$excerpt = wp_trim_words( $excerpt, 55, ' …' );
	return $excerpt;
}

/**
 * Generates Blog Card HTML.
 *
 * @param int $post_id The post ID.
 * @param string|array $size Optional. Image size to use. Accepts any valid image size, or an array of width and height values in pixels (in that order). Default array( 150, 150 ).
 * @return string Blog Card HTML.
 */
function get_blog_card( $post_id, $size = array( 150, 150 ) ) {
	$html = '';

	$post_query = new WP_Query( array(
		'p' => $post_id,
		'post_type' => 'any',
		'posts_per_page' => 1,
	) );
	if ( $post_query->have_posts() ) {
		while ( $post_query->have_posts() ) {
			$post_query->the_post();

			$permalink = get_permalink();

			$html .= '<div class="blog-card">';
			$html .= ( has_post_thumbnail() ? '<div class="blog-card-thumbnail"><a href="' . $permalink . '">' . get_the_post_thumbnail( null, $size ) . '</a></div>' : '' );
			$html .= '<div class="blog-card-content">';
			$html .= '<div class="blog-card-title"><a href="' .  $permalink . '">' . get_the_title() . '</a></div>';
			$html .= '<div class="blog-card-excerpt">' . get_excerpt_for_blog_card( $post_query->post ) . '</div>';
			$html .= '<div class="blog-card-footer"><span class="blog-card-more"><a href="' . $permalink . '">' . __( '記事を読む' ) . '</a></span></div>';
			$html .= '</div>';
			$html .= '</div>';
		}
		wp_reset_postdata();
	}

	return $html;
}

/**
 * embed_oembed_html wraps the filter.
 */
function blog_card_site_oembed_html( $html, $url ) {
	$post_id = url_to_postid( $url );
	if ( $post_id && ! is_admin() ) {
		$html = get_blog_card( $post_id );
	}
	return $html;
}

add_filter( 'embed_oembed_html', 'blog_card_site_oembed_html', 100, 2 );

スタイル(CSS)のサンプルは下記の通りです。

/*
Blog Card
*/
.blog-card {
	margin-bottom: 10px;
	padding: 15px;
	border: 1px solid #ccc;
	border-radius: 3px;
}
.blog-card:after {
	content: " "; 
	display: block;
	clear: both;
}
.blog-card-thumbnail {
	float: left;
	margin-right: 15px;
}
.blog-card-thumbnail img {
	object-fit: cover;
	width: 150px;
}
.blog-card-title {
	line-height: 1.4;
	margin: 0 0 0.75em;
	padding: 0;
	color: #333;
	font-size: 1.4rem;
	font-weight: 800;
}
.blog-card-title a {
	color: #333;
	text-decoration: none;
}
.blog-card-title a:visited {
	color: #444;
}
.blog-card-footer {
	margin-top: 0.25em
}

エディタ内

なお、上記のコードは、エディタ内では内部ブログカードでも標準の埋め込みコードを表示するようにしています。エディタ内においても、内部ブログカードを表示する場合は、下記のように変更してください。

変更前:

function blog_card_site_oembed_html( $html, $url ) {
	$post_id = url_to_postid( $url );
	if ( $post_id && ! is_admin() ) {
		$html = get_blog_card( $post_id );
	}
	return $html;
}

変更後:

function blog_card_site_oembed_html( $html, $url ) {
	$post_id = url_to_postid( $url );
	if ( $post_id ) {
		$html = get_blog_card( $post_id );
	}
	return $html;
}

また、エディタ用スタイルシート(editor-style.css)にも、スタイルを追記してください。

コメント

  • ishitakaさま

    いつも勝手に参考にさせていただいております。
    まさに私のやりたかった事が、このブログカードだったのですが、いまいち作り方が分かりません。
    例えば、記事を投稿する際に特定のカテゴリー にチェックを入れて公開するとトップページにこのブログカードが表示されるようにしたいと思っています。

    お忙しい中、大変ご迷惑とは思いますが、お時間のございます時に教えていただけないでしょうか?

    よろしくお願いします。

    • こんにちは、コメントありがとうございます。
      ブログカードは、表示したい場所に表示先の URL を1行で記述するだけですよ。
      ショートコードで表示する場合は、下記のように記述します。
      [embed]https://example.com/hello-world/[/embed]
      以上、よろしくお願いします。

  • 石鷹さま

    お忙しい中、早速のご回答ありがとうございます。
    おっしゃる通り、私でも簡単にできました!

    ただ、表示される画像が本文中の画像ではなく、アイキャッチで設定した画像になってしまいます。任意の画像にすることも出来ますか?
    上段で教えていただいた、phpとcssは追記してあります。

    また、このブログカード自体のサイズは任意のサイズに変更も出来ますか?

    よろしくお願いします。

    • そうなってくると、普通に「メディアと文章」ブロックあたりで編集画面に直接記述された方がいいかと思います。
      メディアと文章ブロックであれば、こちらの記事などが参考になると思います。

  • なるほど!それも試してみます。
    丁寧にありがとうございました。
    また、よろしくお願いします。

  • いつもお世話になっております。
    色々と試しており、「URL を1行で記述するだけ」という意味をようやく理解し、改めてこのコードの利便さを実感しました!

    一つ質問させてください。
    現状ですと、クリック/タップできる範囲が「タイトル」や「サムネイル」、「記事を読む」の部分なのですが、その範囲を枠内全体に広げることはできますか?

    お時間のあるときに教えてください。
    どうぞよろしくお願いします。

    • こんにちは
      コードの38行目から45行目を下記のように変更するとできると思います。

      $html .= '<div class="blog-card">';
      $html .= ( has_post_thumbnail() ? '<div class="blog-card-thumbnail"><a href="' . $permalink . '">' . get_the_post_thumbnail( null, $size ) . '</a></div>' : '' );
      $html .= '<div class="blog-card-content">';
      $html .= '<div class="blog-card-title"><a href="' . $permalink . '">' . get_the_title() . '</a></div>';
      $html .= '<div class="blog-card-excerpt">' . get_excerpt_for_blog_card( $post_query->post ) . '</div>';
      $html .= '<div class="blog-card-footer"><span class="blog-card-more"><a href="' . $permalink . '">' . __( '記事を読む' ) . '</a></span></div>';
      $html .= '</div>';
      $html .= '</div>';


      $html .= '<a href="' . $permalink . '"><div class="blog-card">';
      $html .= ( has_post_thumbnail() ? '<div class="blog-card-thumbnail">' . get_the_post_thumbnail( null, $size ) . '</div>' : '' );
      $html .= '<div class="blog-card-content">';
      $html .= '<div class="blog-card-title">' . get_the_title() . '</div>';
      $html .= '<div class="blog-card-excerpt">' . get_excerpt_for_blog_card( $post_query->post ) . '</div>';
      $html .= '<div class="blog-card-footer"><span class="blog-card-more">' . __( '記事を読む' ) . '</span></div>';
      $html .= '</div>';
      $html .= '</div></a>';

  • 石鷹さま

    完璧です!!
    無事に出来ました。
    本当にお忙しい中、いつもありがとうございます。

    大切に使わせていただきます。

浅賀崇 へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。

日本語でコメントを入力してください。(スパム対策)