【AMP対応】おしゃれな内部・外部リンク用自作ブログカード

ブログにおいて内部リンク・外部リンクを使用する際にただのテキストリンクだと味気ない感じがするかと思います。

そこでiframelyやPz-LinkCardなど使用してみましたが、AMPでの表示に対応していませんでした。そのため、ただのテキストリンクになったり、そもそも何も表示されなかったり、使い物にならないことが多々あり、AMPを辞めるかどうかも考えました。

以下にiframelyのリンクを記載。(AMP非対応)

以下は自作ブログカード。

UMilCL
UMilCL
本記事では誰でもできるAMP対応のおしゃれなiframelyのようなブログカードの作り方について詳しく解説します。

コードの追加方法

コードはfunction.php、HTMLコードとCSSの3つがあります。以下に追加方法とコードについて記載します。

実装については以下のサイトを参考にさせていただきました。<span>タグで囲った<a>タグをブログカード化するという特殊な方法です。

別で作成したアフィリエイトリンクカードが同じようにHTMLのカスタムコードをエディタで張り付けて使用する使い方であったため、同じで使いやすそうであったので使用させてもらいました。

function.phpのコード追加方法

基本的には使わせていただいた上記サイトのコードそのままです。自分が詰まった箇所やカスタマイズした箇所を詳しく記載します。

私のテーマはNewspaperであり、td-composerでモバイル用の表示を作成しています。AMP対応のためにfunction.phpは通常とAMPページように以下の2か所の変更が必要です。

FTPか何かでサーバからファイルをダウンロードして、ファイルを編集してアップロードください。修正により描画がおかしくなった場合に対応可能なようにファイルはバックアップしておいてください。

通常ページ用:wordpress/wp-content/themes/Newspaper/function.php
AMPページ用:wordpress/wp-content/plugins/td-composer/mobile/function.php

//修正したfunctions.phpでの記述 //個別記事でのみblog-card.phpを読み込む //@link https://wordpress.stackexchange.com/questions/249931/how-to-load-file-only-in-single-post-page-through-function-php add_action( 'wp', 'cb_include_blog_card' ); function cb_include_blog_card() { if( is_single() || is_page() ) { require get_template_directory(). '/lib/blog-card.php'; //ブログカード関係の関数 } }

blog-card.phpとOpenGraph.phpのファイルの保存

function.phpから参照する関数をblog-card.phpとOpenGraph.phpで定義しています。私がカスタマイズしたblog-card.phpは以下のダウンロードリンクから取得可能です。

また追加でOpenGraph.phpというファイルが必要になりますので、以下のサイトから取得できます。

「Clone or download」から「Download ZIP」をクリックして、ファイルをダウンロードしてください。

blog-card.phpと先ほどダウンロードしたOpenGraph.phpを以下のフォルダに保存します。

通常ページ用:wordpress/wp-content/themes/Newspaper/lib/
AMPページ用:wordpress/wp-content/plugins/td-composer/mobile/lib/

blog-card.phpの修正内容説明

blog-card.phpはちろちろちろりん様が作成されたもので、ほぼほぼそのまま使用させていただいています。

ただし、AddThisのソーシャルシェアボタンを使用する場合にそのまま使用するとインライン内ではなく、ブログカード内にソーシャルシェアボタンが作成されるバグが発生したため、内部リンクの抜粋の取得方法を修正しています。

抜粋を取得する際に、get_the_excerpt($id) そのままではなく、抜粋の文章をトリムし、取得すると内部リンク内にソーシャルシェアボタンが作成されないようになったので、そのように修正しています。

//$excerpt = get_post_meta($id, 'meta_description', true) ? get_post_meta($id,'meta_description',true) : get_the_excerpt($id); //$post_data->post_excerpt; //抜粋の取得 $excerpt = get_post_meta($id, 'meta_description', true) ? wp_trim_words(strip_shortcodes(get_post_meta($id,'meta_description',true)), 150, '…' ) : wp_trim_words(strip_shortcodes(get_the_excerpt($id)), 150, '…' ); //$post_data->post_excerpt; //抜粋の取得
<?php /** * 外部サイトのOGP:imageに設定されている画像を、自分のサーバーの任意のディレクトリに保存する * @param string image_url (OGP:imageのURL) * @return string path(自サーバーでのファイルパス) **/ if (!function_exists('cb_fetch_ogp_image_file')): function cb_fetch_ogp_image_file ( $image_url ) { //WP_Filesystemの使用 require_once(ABSPATH . 'wp-admin/includes/file.php'); require_once(ABSPATH . 'wp-admin/includes/image.php'); //require_once(ABSPATH . 'wp-admin/includes/media.php'); // サーバーの画像を保存するディレクトリを設定 $dir = ABSPATH . 'wp-content/uploads/elink-img/'; $image_name = hash('md5', $image_url, FALSE); // ファイルURLからファイル名を決める $image_lists = glob($dir .'*', GLOB_NOSORT); // $dirでのファイルのリストを取得 $file_existance = preg_grep("/$image_name/", $image_lists); //ファイルの有無を確認 if (!$file_existance): //ファイルがなかったら、画像を取得・保存する if ( WP_Filesystem() ): //WP_Filesystemの初期化 global $wp_filesystem;//$wp_filesystemオブジェクトの呼び出し // 画像のバイナリデータを取得しておく $image_data = $wp_filesystem->get_contents($image_url); //拡張子をファイル名から取得できるならする $tmp_image_url = preg_replace('/\?.*$/i', '', $image_url); //URLの?以降を削除する $tmp_extension = preg_replace('/^.*\.([^.]+)$/D', '$1', $tmp_image_url); $allow_extensions = array('png', 'jpg', 'jpeg', 'gif' ); //許容する拡張子のリスト if ($image_data): //もし拡張子がゲットできていなかったら、画像データを精査 if ( !in_array($tmp_extension, $allow_extensions) ): // MIME Typeをチェック $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_buffer($finfo, $image_data); finfo_close($finfo); switch ($mime) { //拡張子の決定 case "image/jpeg": $extension = '.jpg'; break; case "image/png": $extension = '.png'; break; case "image/gif": $extension = '.gif'; break; default: echo "対応していない画像ファイル"; } else: //拡張子が取得できていたら、それを設定する $extension = '.'. $tmp_extension; endif; //画像を保存する $wp_filesystem->put_contents($dir. "cb_" .$image_name. $extension, $image_data); //画像を編集する //@link: https://developer.wordpress.org/reference/classes/wp_image_editor/ $image_editor = wp_get_image_editor($dir. "cb_" .$image_name. $extension); if ( !is_wp_error($image_editor) ): //画像編集オブジェクトに画像が正常に読み込めたら $image_editor->resize(400, 400, false); //画像のリサイズ $image_editor->save( $dir. "cb_" .$image_name. $extension ); //編集した画像の保存 else: return; //echo "image_editor error"; endif; $upload_dir = wp_upload_dir(); return $upload_dir['baseurl'] . "/elink-img/cb_" .$image_name. $extension; else: //画像のバイナリデータが取得できていなかったら return get_template_directory_uri() . '/images/ogp_no_image.jpg'; //用意しておいた画像を使う //echo "画像データ取得できず"; endif; endif; // WP_Filesystem() else: // ファイルがあったら、ファイル名を取得する //echo 'preg_match作動 すでにファイルあり'; $filename = array_shift($file_existance); //ローカルパス($dir/$image_name.$extension)形式 $filename = str_replace($dir,"",$filename); $upload_dir = wp_upload_dir(); return $upload_dir['baseurl'] . "/elink-img/" .$filename; endif; } endif; /** * 投稿画面の本文からブログカードに変換する部分をピックアップして、ブログカードのHTMLコードに置換する * @param string the_content(投稿本文) * @return string the_content(ブログカード用に置換された投稿本文) **/ if (!function_exists('cb_original_blog_card')): function cb_original_blog_card ( $the_content ) { // 関連情報を取得するための正規表現 $pattern = '#<span class="bcard (i|e)link"><a href="((?:https?|ftp)(?:://.+?))" title="(.*?)"(?: target="_blank")?>(.*?)</a></span>#'; // 一致する文字列を取得する preg_match_all($pattern, $the_content, $card_matches, PREG_SET_ORDER); /* 以下のような配列に格納される array(N) { [M]=> array(5) { [0]=> mathced content [1]=> $1 : Link type (i|e) [2]=> $2 : URL [3]=> $3 : Title [4]=> $4 : Link Text } }*/ if ($card_matches) { //変換する要素があるならば foreach ($card_matches as $m) { $url = $m[2]; $domain = parse_url($url, PHP_URL_HOST); if ($m[1] == 'i') : //内部リンクの場合 $id = url_to_postid( $url ); //IDを取得(URLから投稿ID変換) if ( !$id ) return ''; //IDを取得できない場合は脱出 //global $postの利用 $post_data = get_post($id); setup_postdata($post_data); $title = $post_data->post_title; //タイトルの取得 //$excerpt = get_post_meta($id, 'meta_description', true) ? get_post_meta($id,'meta_description',true) : get_the_excerpt($id); //$post_data->post_excerpt; //抜粋の取得 $excerpt = get_post_meta($id, 'meta_description', true) ? wp_trim_words(strip_shortcodes(get_post_meta($id,'meta_description',true)), 150, '…' ) : wp_trim_words(strip_shortcodes(get_the_excerpt($id)), 150, '…' ); //$post_data->post_excerpt; //抜粋の取得 if ( has_post_thumbnail($id) ): //thumbnail画像のHTML取得 $src = get_the_post_thumbnail( $id, 'cb400-400', array( 'alt' => $title ) ); $thumbnail = '<div class="blog-card-thumbnail">' .$src. '</div>'; else: //thumbnailがない場合 $src = get_template_directory_uri() . '/images/ogp_no_image.jpg'; $thumbnail = '<div class="blog-card-thumbnail"><img src="' .$src. '"></div>'; endif; $date = date('Y-m-d', strtotime($post_data->post_date)); //投稿日の取得 $target = ''; //target="_blank"の設定 wp_reset_postdata(); elseif ($m[1] == 'e') : //外部リンクの場合 //OGP情報を利用する($graph objectの定義のため、ここで先に読み込む) require_once('OpenGraph.php'); //@link https://github.com/scottmac/opengraph //キャッシュを利用する $url_transient = 'bcard_'. md5($url); //set_transient, get_transient用の変数を設定する $graph = get_transient($url_transient); //キャッシュがないか確認 //@link https://developer.wordpress.org/reference/functions/get_transient/ if ($graph === false): //キャッシュがなかったらopengraph.phpで情報を取得する $graph = OpenGraph::fetch($url); endif; if (!($graph === false)) : //OGP情報が設定されていたら $title = $graph->title ? $graph->title : $m[3]; $excerpt = $graph->description ? $graph->description : ''; $src = $graph->image ? cb_fetch_ogp_image_file($graph->image) : get_template_directory_uri().'/images/ogp_no_image.jpg'; $thumbnail = '<div class="blog-card-thumbnail"><img class="wp-post-image" src="' .$src. '"alt="' .$m[3]. '"></div>'; set_transient($url_transient, $graph, DAY_IN_SECONDS * 30); //30日間データベースにキャッシュを保存 //@link https://developer.wordpress.org/reference/functions/set_transient/ endif; $date = ''; //外部リンクは投稿日なし $target = 'target="_blank"'; //外部リンクは新規タブで endif; //ブログカードのタグを設定 $title_tag = '<section class="blog-card__title">' .$title. '</section>'; $date_tag = '<section class="blog-card__date">' .$date. '</section>'; $excerpt_tag = '<section class="blog-card__excerpt">' .$excerpt. '</section>'; $domain_tag = '<section class="blog-card__domain">' .$domain. '</section>'; //タグを合体 $whole_tag = '<div class="blog-card"><a href="' .$url. '"' .$target. '>'.$thumbnail .'<div class="blog-card-body">' .$title_tag .$date_tag .$excerpt_tag. $domain_tag. '</div></a></div>'; //置換する $the_content = preg_replace('{'.preg_quote($m[0]).'}', $whole_tag, $the_content); } } return $the_content; } endif; add_filter('the_content', 'cb_original_blog_card', 11);

OpenGraph.phpとは?

OpenGraph.phpとは、他のブログのタイトル、イメージ、詳細などを取得するOGPの処理を記載したphpファイルです。

OGPとは、「Open Graph Protcol」の略でブログやFacebookやTwitterなどのSNSでシェアした際に、設定したWEBページのタイトルやイメージ画像、詳細などを正しく伝えるためのHTML要素です。

私のブログもWordPressのプラグインの「All in One SEO」にてOGP情報を設定しています。

OGPを設定すると他のブログやSNS上でURLが共有された際に、OGPを使用して設定しておいたタイトルや画像、説明文などが表示されるようになります。

imageファイルの保存場所

OpenGraphで取得したサムネイルは以下のフォルダに保存されるので、フォルダを作成しておきます。

wordpress/wp-content/upload/elink-img/

またサムネイルが取得できない、設定されていない場合に使用されるサムネイルを設定します。

サムネイルがない場合の画像

通常ページ用:wordpress/wp-content/themes/Newspaper/images/ogp_no_image.jpg
AMPページ用:wordpress/wp-content/plugins/td-composer/mobile /images/ogp_no_image.jpg

CSSコードの追加方法

CSSについては追加CSSかstyle.cssのどちらかに記載し、表示をおしゃれに変更します。追加CSSについてはWordPressであればダッシュボードから、外観→カスタマイズ→追加CSSで簡単にCSSの追加設定が可能です。

またstyle.cssについても 外観→テーマエディター→style.cssの最後の部分に追加することで設定変更可能です。

枠線の色や背景色はコメント箇所のカラーコード差し替えで変更可能です。またボタン等にマウスを移動した際に透過度を変更したり、少し浮き出るようなエフェクトが参考コードに入っていておしゃれです。

CSSはいくつか以下の変更を加えています。

  1. 「関連記事」という文言を左上に追加
  2. ブログカードの幅をフルサイズに
  3. タイトルをフルで表示するように2行表示に変更
  4. 抜粋を逆に2行に変更
  5. ドメイン、投稿日を細かく修正(サイズ、位置など)
.blog-card { width: 100%; max-width:600px; border: none; background-color: #fefefe; /*box-shadow: 0 3px 5px rgba(0, 0, 0, 0.06);*/ -webkit-filter:drop-shadow(1px 3px 5px rgba(0, 0, 0, 0.2)); -moz-filter:drop-shadow(1px 3px 5px rgba(0, 0, 0, 0.2)); -ms-filter:drop-shadow(1px 3px 5px rgba(0, 0, 0, 0.2)); filter:drop-shadow(1px 3px 5px rgba(0, 0, 0, 0.2)); margin: 1.6rem 0; } @media only screen and (min-width: 0) { /*スマホのとき*/ .blog-card{ min-height:140px; } } @media only screen and (min-width: 768px) { /*タブレット以上のとき*/ .blog-card{ min-height:160px; } } .blog-card:before { font-family: FontAwesome; position: absolute; padding: 2px 6px; /*content: "関連記事";*/ background-color: #dedede; color: #696969; font-size: .7em; z-index: 1; } .blog-card a { line-height: 1.9em; text-decoration: none; color: #5d686f; display: grid; overflow: hidden; } @media only screen and (min-width: 0) { /*スマホのとき*/ .blog-card a { grid-template-columns: 140px fit-content(100%); } } @media only screen and (min-width: 768px) { /*タブレット以上のとき*/ .blog-card a { grid-template-columns: 160px fit-content(100%); } } .blog-card a:hover { text-decoration: none; } /*ブログカードの左側:サムネイル画像*/ .blog-card-thumbnail { grid-column: 1; } @media only screen and (min-width: 0) { /*スマホのとき*/ .blog-card-thumbnail { width: 140px; height: 140px; } } @media only screen and (min-width: 768px) { /*タブレット以上のとき*/ .blog-card-thumbnail { width: 160px; height: 160px; } } .blog-card-thumbnail img { object-fit: cover; } @media only screen and (min-width: 0) { /*スマホのとき*/ .blog-card-thumbnail img { width: 140px; height: 140px; } } @media only screen and (min-width: 768px) { /*タブレット以上のとき*/ .blog-card-thumbnail img { width: 160px; height: 160px; } } /*ブログカードの右側:タイトル・日付・抜粋・ドメイン名*/ .blog-card-body { position: relative; grid-column: 2; padding: 8px 10px; overflow: hidden; } .blog-card__title {/*ブログカードの記事タイトル*/ font-weight: 700; max-height: 3.8em; margin: 0 !important; overflow: hidden; } .blog-card__date {/*ブログカードの記事投稿日*/ position: absolute; bottom: 10px; right: 20px; font-size: 12px; margin: 0 !important; } .blog-card__excerpt {/*ブログカードの記事抜粋*/ font-size: 13px; line-height: 1.6em; margin: 5px !important; overflow: hidden; } /*ブログカードの記事抜粋が長い場合に備えて、高さを指定*/ @media only screen and (min-width: 0) { /*スマホのとき*/ .blog-card__excerpt { max-height: 3.2em; } } @media only screen and (min-width: 768px) { /*タブレット以上のとき*/ .blog-card__excerpt { max-height: 3.2em; } } .blog-card__domain { position: absolute; bottom: 10px; left: 15px; font-size: 12px; color: #999; } /*hover時のエフェクト設定*/ img.wp-post-image { transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1); transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1); } a:hover img.wp-post-image { -webkit-transform: scale(1.03); transform: scale(1.03); }

エディタでのHTMLコードの追加方法

HTMLコードは記事の内部にブログカードを追加する度に記載します。そのため簡単に利用するために再利用ブロックを使用しています。

新エディタのGutenbergであれば、再利用ブロックとして登録して簡単に追加できます。使用する際は「URL」、「タイトル」、「表示文字」を追加するだけで使用できます。

「タイトル」と「表示文字」は同じで問題ありません。またブログカードとして使用している間は自動的にタイトルなどは取得しますので、あまり気にする必要はありません。

<span class="bcard ilink"><a href="URL差し替え" title="タイトル差し替え" target="_blank" rel="noopener noreferrer">表示文字差し替え</a></span>
<span class="bcard elink"><a href="URL差し替え" title="タイトル差し替え" target="_blank" rel="nofollow noopener noreferrer">表示文字差し替え</a></span>

最後に

今回の記事ではちろちろちろりん様のサイトを参考に、簡単におしゃれなブログカードを作成できる方法について説明しました。

CSSを修正すればデザインの変更も可能なので、皆さんも試してみてください。

また気に入っていただければ、Twitter(@umilcl)やFacebookもフォローしていただければ幸いです。

以下は以前に紹介したアフィリエイト用のブログカードの作り方を紹介した記事です。

UMilCLhttps://umilcl.com
兼業ブロガー。メインは大手製造業システム企画・設計・プロジェクト管理。工場のプロセス制御が主な業務。 得意分野: プロセス制御と統計、機械学習、画像処理、システム技術 保有資格: プロジェクトマネージャー、情報処理安全確保支援士、ネットワークスペシャリスト、応用情報処理、第一種衛生管理者

Similar Articles

Comments

返事を書く

コメントを入力してください!
ここに名前を入力してください

Follow US

1ファンいいね
6フォロワーフォロー
89フォロワーフォロー
4,247フォロワーフォロー
0SubscribersSubscribe

Archive

Most Popular

Synology DS220j DS220+の比較・レビュー

SynologyのエントリーモデルのDS220jとDS220+が発売され、2020年モデルもある程度そろってきました。 DS220はエントリークラス、DS220+はフラッグシップモデルとなりますが、違いはどこにあるか調査しました。

Synology DS220j レビュー【エントリーモデル後継機】

SynologyのエントリーモデルのDS218jの後継機が発売されたので、改善点と問題点をまとめています。 簡単にまとめると大変コスパのよいエントリーモデルのNASを踏襲した機能向上が行われており、上位機種とのスペックを要求する機能の差別化はそのままです。

Synology DS220+と他DS+シリーズ3種の比較・レビュー

SynologyのDS220+、DS420+、DS720+、DS920+の2ベイと4ベイのDS+シリーズが4機種の後継機が5月20日に発売されました。DS+シリーズ4種のスペックについて比較していますので、購入時の参考にしてみてください。

Windows10のHyper-V環境へのCentOS 8のインストール方法

この投稿では検索にてHyper-V環境へのCentOS8インストールを見に来てくれた方がいたので、CentOS7だけでなく、Windows 10上のHyper-V環境へのCentOS 8.1のインストール方法についても今回投稿します。

【2020年1月】子育て中ママが端末購入するならOPPO Reno A【購入後レビュー有】

妻のスマホ(Google Pixel 3a)が購入から5か月で子供の手により水没したので、防水性能の高い楽天モバイルより発売されているOppoのおすすめの最新機種「OPPO Reno A」の購入を検討した内容を紹介します。