WordPressのデフォルトブログカードってなんかそっけないし、SP時も場所取るな。。。
それに他サイトの情報も取得できないし何かと不便。。。
ということで、今回は他サイトの情報取得にも対応したブログカードを割りとガチで作ってみたいと思います。
といっても他サイトに迷惑がかかってはいけないので、画像の直リンクは避けて、できるだけミニマムに取得してきます。
また、ブログカードはデザインしやすいように、関数ファイルとテンプレートファイルで分けます。
尚、ブログカード自体はショートコードで内容を設定できるようにしていきます。
それではいってみましょう!
# この記事で解決すること
- デザインの自由度が高いブログカードを作成することができる
- 外部サイトのURLに対応したブログカードを作成することができる
手順
- 事前準備
- 前提
- フォルダ構成の確認
- 仕様の確認
- 初期設定
- メインの変数について
- テンプレートURLの判別
- 外部サイトの情報取得
- メイン関数の処理
- 初期変数の設定
- ショートコード用のattributeの設定
- ドメインの判別
- サイトアイコン・サイト名の処理
- idを取得
- タイトル・説明文の処理
- 画像の処理
- データの整理
- templateにargumentを渡す
- テンプレートの実装
- phpファイルの処理
- cssファイルの処理
- ショートコードの呼び出し設定
- jsの処理
- phpの処理
- 実装
事前準備
前提
今回はWordpressに機能を追加しますので、Wordpressを使用している必要があります。
また、1行だけですがfunctions.phpを編集しますので、それができる方が対象となります。
フォルダ構成の確認
- theme_name
- functions
- addBlogCard
- assets
- no-image.png
- site-icon.png
- youtube.png(救済)
- addBlogCard.php(メイン)
- addBlogCard-template.php(UI)
- addBlogCard.css(UI)
- addBlogCard-tinymce.php(shortcode)
- addBlogCard.js(shortcode)
- assets
- addBlogCard
- functions.php
- …
- functions
仕様の確認
最終形態のサンプルとしては以下の内容となります。
同一ドメイン
外部URL
極力ファイルは増やしたくないので、今回は外部URLの情報をcurlとxpathで取得します。
また、外部URLの場合はサイトアイコンとサイト名、アイキャッチ画像は以下の理由から取得しません。
※youtubeなどのよくリンクさせるであろうサイトのために救済作を用意しております。
サイトアイコン, アイキャッチ画像
- 画像直リンクになるため
- 自サバに画像を保存することはできるがそこまでの価値を感じないため
サイト名
- サイトによっては設定していないため
また、ショートコードは下記の3パターン用意します。([]は省いてます)
// 簡易
blog_card url=""
// カテゴリー等一覧(タクソノミー用)
blog_card url="URL" tax="taxonomy_name" id="term_id"
// フル(外部サイト・詳細設定用)
blog_card url="URL" title="タイトル" excerpt="説明" thumb="media_id"
初期設定
メインの変数について
今回ショートコードから取得するattributeは下記のとおりです。
name | remark |
---|---|
url | 表示させるページのURL |
title | タイトルを自分で設定したい場合に使用 |
excerpt | 抜粋文を自分で設定したい場合に使用 |
thumb | 表示アイキャッチ画像を自分で設定したい場合に メディアのIDを設定して使用 |
tax | カテゴリー一覧などのタクソノミーページを取得する際に使用 |
id | タクソノミーページを取得する際にterm_idを設定 |
テンプレートURLの判別
WordPressを使用している方の中には子テーマを使用している方もいますので、その処理を書いておきます。
参照先はaddBlogCard内部のみなのでaddBlogCardまで書いておきます。
addBlogCard.php
function addBlogCard_get_template_url() {
if(is_child_theme()) {
return get_stylesheet_directory_uri().'/functions/addBlogCard';
} else {
return get_template_directory_uri().'/functions/addBlogCard';
}
}
外部サイトの情報取得
外部サイトの情報を取得しないといけないことがわかっていますので、先に取得しておきましょう。
addBlogCard.php
function addBlogCard_get_data( $url ) {
$headers = array(
"HTTP/1.0",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language:ja,en-US;q=0.9,en;q=0.8",
"Connection:keep-alive",
"User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
$dom = new DOMDocument();
$html = mb_convert_encoding($result, "HTML-ENTITIES", "auto");
@$dom -> loadHTML($html);
$xpath = new DOMXPath($dom);
$xpath -> registerNamespace("php", "http://php.net/xpath");
$xpath -> registerPHPFunctions();
return $xpath;
}
header情報は何でも良いので、このサイトの情報からご自身の環境に差し替えて使用してください。
「説明すると長くなる」+「古い技術」ということで、curl
とxpath
に関してはあえて説明しません。
また機会があれば別記事で説明します。
メイン関数の処理
メインの関数はaddBlogCard()
とします。
addBlogCard.php
function addBlogCard($atts) {
}
$atts
にショートコードのurl="hoge"
とかが入ってくると思ってください。
初期変数の設定
画像の大きさやアイコンのURLなどはファイルの上の方に書いておいたほうが編集に迷わないので、グローバル関数にしてaddBlogCard
に呼び出します。
addBlogCard.php
$img_width = 90; // アイキャッチ画像サイズの幅指定
$img_height = 90; // アイキャッチ画像サイズの高さ指定
$length = 100; // post_excerptがなかった場合の文字数
$site_icon = addBlogCard_get_template_url().'/assets/site-icon.png'; // サイトアイコンの画像URLを指定
$no_image = addBlogCard_get_template_url().'/assets/no-image.png'; // アイキャッチ画像がない場合の画像URLを指定
function addBlogCard($atts) {
global $img_width, $img_height, $site_icon, $no_image;
}
$lengthに関してはテストしていたサイトが、post_excerpt
がなかったので入れています。
それ以外は見ての通りです。
ショートコード用のattributeの設定
では、受け取ったurl="hoge"
とかを配列に入れます。
addBlogCard.php: addBlogCard
extract(shortcode_atts(array(
'url' => "",
'title' => "",
'excerpt' => "",
'thumb' => "",
// taxonomy用
'tax' => "",
'id' => ""
), $atts));
extract
を使用することで'url' => ""
が$url
に変わってくれます。
extract
とshortcode_atts
の組み合わせは非推奨なのですが、
すごく便利なので重要な情報を扱う場合以外は使用しても大丈夫だと思っています。
※個人的見解です
これでショートコードから受け取ったattributeを変数として受け取ることができました。
ドメインの判別
URLが内部のものか、外部のものかを判別していきます。
addBlogCard.php: addBlogCard
$my_site = stristr($url, $_SERVER['HTTP_HOST']);
$_SERVER['HTTP_HOST']
表示しているページのドメイン(ex: brandnew.work)
$url
ショートコードから受け取ったURL
stristr(hoge, fuga)
大文字小文字を区別せずhoge
からfuga
を検索
stristr
の返り値は、文字列があればhoge
をそのまま、なければfalse
となります。
これで、内部URLか外部URLかの判別ができました。
サイトアイコン・サイト名の処理
前述の通り、外部サイトの場合はサイトアイコンとサイト名を取得しませんので、それも踏まえて処理していきます。
addBlogCard.php: addBlogCard
if($my_site !== false) {
// 同サイトの場合
$site_name = get_bloginfo( 'name' );
$site = isset($site_icon) ? "<img src='{$site_icon}' width='16' height='16' alt='{$site_name}'>{$site_name}" : "";
} elseif(stristr($url, 'youtube.com') || stristr($url, 'youtu.be')) {
// youtubeの場合
$site_name = 'youtube';
$site = "<img src='".addBlogCard_get_template_url()."/assets/youtube.png' width='16' height='16' alt='{$site_name}'>{$site_name}";
}
7行目~
youtubeなどのよく使用するサイトは救済措置としてサイト名とサイトアイコンを設定しています
idを取得
次項でtitle
とexcerpt
を取得しますので、事前にidを取得しておきます。
※前項のコードと合体させて問題ないです。
addBlogCard.php: addBlogCard
if($my_site !== false) {
$id = empty($id) ? url_to_postid($url) : $id;
}
「$idがショートコード側で設定されていない場合」=「タクソノミー一覧ではない場合」は、url_to_postid
でid
を取得します。
タイトル・説明文の処理
addBlogCard.php
function addBlogCard_excerpt($post_id) {
global $length;
$post = get_post($post_id);
if($post->post_excerpt) {
// excerptが入力されている場合
$return = $post->post_excerpt;
} else {
// excerptが入力されていない場合
$return = $post->post_content;
$return = addBlogCard_flat_text($return);
if(mb_strlen($return) > $length) {
// $lengthよりも文字数が多い場合の対処
$return = mb_substr($return, 0, $length);
$return .= '...';
}
}
return $return;
}
2行目
一番最初に定義した$length
を呼び出します。
また、抜粋文自体が「決められた文字数の中で内容をわかりやすく説明する」という概念なので、
この$length
は抜粋文が設定されていない場合にしか機能しません。
15~19行目
$return
の長さと$length
を比較して、$length
よりも$return
文字数が多い場合に、
mb_substr
で文字数を$length
の長さにあわせています。
抜粋文後の「…」が必要ない場合は18行目を削除してください。
上記を用いて表示するタイトルと説明文を取得していきます。
addBlogCard.php: addBlogCard
if( $my_site === false ) {
// youtube以外の外部サイトの場合 ------------------------------------------------------------
// 外部サイトの情報取得
$xpath = addBlogCard_get_data($url);
// title取得
if(empty($title)) {
$title = $xpath->query('//head/title[1]') ? $xpath->query('//head/title[1]')->item(0)->nodeValue : "";
}
// excerpt取得
if(empty($excerpt)) {
if($xpath->query('//meta[@property="og:description"]')[0]) {
$excerpt = $xpath->query('//meta[@property="og:description"]/@content')[0]->textContent;
} else if($xpath->query('//meta[@name="description"]')[0]) {
$excerpt = $xpath->query('//meta[@name="description"]/@content')[0]->textContent;
} else {
$excerpt = "";
}
}
} else if(empty($tax)) {
// タクソノミー一覧ではない場合の取得 ------------------------------------------------------------
$title = empty($title) ? get_the_title($id) : $title;
$excerpt = empty($excerpt) ? addBlogCard_excerpt($id) : $excerpt;
} else if(!empty($tax)) {
// タクソノミー一覧の取得 ------------------------------------------------------------
$term = get_term( $id, $tax );
$title = empty($title) ? $term->name : $title;
$excerpt = empty($excerpt) ? term_description($id, $tax) : $excerpt;
}
xpathの説明は省きますので、リファレンスをご覧ください。
10行目
og:description
の取得を先に持ってきているのは、検証していたサイトになぜかdescription
がなかったからです。
画像の処理
アイキャッチ画像のURLを取得していきます。
事前次項として、ショートコードのthumbに画像idを設定することで画像が表示されるようにします。
addBlogCard.php: addBlogCard
if(wp_get_attachment_url($thumb)) {
// サムネイルが設定されている場合 ------------------------------------------------------------
$img = wp_get_attachment_image_url($thumb, array($img_width,$img_height));
$img_tag = "<img src='{$img}' alt='{$title}' width='{$img_width}' height='{$img_height}'>";
} elseif( empty($tax) && $my_site !== false ) {
// 通常 ------------------------------------------------------------
if(has_post_thumbnail($id)) {
$img = wp_get_attachment_image_src(get_post_thumbnail_id($id), array($img_width,$img_height));
$img_tag = "<img src='{$img[0]}' alt='{$title}' width='{$img[1]}' height='{$img[2]}'>";
}
} elseif(!empty($tax)) {
// taxonomyが設定されている場合(ACFの場合) ------------------------------------------------------------
if(get_field('image', "{$tax}_{$id}")) {
$attachment = get_field('image', "{$tax}_{$id}");
$img_tag = "<img src='{$attachment["sizes"]["thumbnail"]}' alt='{$title}' width='{$img_width}' height='{$img_height}'>";
}
}
全体的にすごく簡単なwordpress関数で構成しています。
13~18行目
termに画像が設定されている場合の呼び出しになります。
私の場合はACFで設定することが多いので上記の設定にしていますが、皆さんはご自身の環境にあわせて必要であればご利用ください。
データの整理
ここでは、titleとexcerptに入っているであろう余計な文字列(空白やhtmlタグ、ショートコードなど)を削除します。
また、エラー回避のために定義されていない変数を空変数として定義しておきます。
まずは不要文字列削除のための関数を用意します。
addBlogCard.php
function addBlogCard_flat_text( $text ) {
$text = strip_shortcodes($text); // ショートコードの削除
$text = wp_strip_all_tags($text); // htmlの削除
$rp = array(' ', ' ', "\xc2\xa0", " ");
$text = str_replace($rp, '', $text); // $rpの文字列削除
return $text;
}
strip_shortcodes
とwp_strip_all_tags
でショートコードとhtmlを削除します。
str_replace(Array, '', $text)
でArray
内に含まれる文字列を$text
から削除してくれます。
正確には”に置換してくれます。
\xc2\xa0
はUTF-8の半角スペースを意味します。
上記のコードを用いてデータを整理します。
addBlogCard.php: addBlogCard
$title = addBlogCard_flat_text($title);
$excerpt = addBlogCard_flat_text($excerpt);
$site = isset($site) ? $site : "";
$img_tag = isset($img_tag) ? $img_tag : "";
$site
と$img_tag
は定義されない場面が出てくるので再定義しています。
templateにargumentを渡す
近年では、get_tempalte_part
の第三引数でargumentを受け取れるようになりましたので、それに伴う処理をしていきます。
addBlogCard.php: addBlogCard
$args = array(
'url' => $url, // リンク先URL
'img_tag' => $img_tag, // アイキャッチ画像
'title' => $title, // タイトル
'excerpt' => $excerpt, // 抜粋文
'site' => $site, // サイトアイコン
);
これをget_template_part
で受け取って表示するのですが、ショートコード内ではすごく困ることになります。
というのもWordpressの仕様上、コンテンツが表示される前にテンプレートが呼び出されます。
そのため、ショートコードを書いた箇所とは別に、ページTOPにもテンプレートが呼び出されることになります。
そのため、受け取る用の関数を用意しておきます。
addBlogCard.php
function addBlogCard_template( $args ) {
ob_start();
get_template_part( 'functions/addBlogCard/addBlogCard', 'template', $args );
return ob_get_clean();
}
ob_start
で一旦表示とは別の場所に保存し、ob_get_clean
で保存した内容を出力していると考えてください。
そして、上記をreturnします。
addBlogCard.php: addBlogCard
return addBlogCard_template( $args );
最後にショートコード化を書いて完了です。
addBlogCard.php
add_shortcode("blog_card", "addBlogCard");
テンプレートの実装
テンプレートを実装していきますが、各々やりたいデザインは異なると思いますので、ざっくり説明していきます。
phpファイルの処理
前項で受け取ったargument
を元に書いています。
addBlogCard-template.php
<a href="<?php echo $args['url'] ?>" target="_blank" class="blog-card">
<div class="blog-card__header">
<?php if(!empty($args['img_tag'])): ?>
<div class="blog-card__thumbnail">
<?php echo $args['img_tag'] ?>
</div>
<?php endif; ?>
<div class="blog-card__content">
<div class="blog-card__title"><?php echo $args['title'] ?></div>
<div class="blog-card__excerpt"><?php echo $args['excerpt'] ?></div>
</div>
</div>
<div class="blog-card__footer">
<div class="blog-card__site"><?php echo $args['site'] ?></div>
<div class="blog-card__more"><span>続きを読む</span></div>
</div>
</a>
cssファイルの処理
あくまでサンプルですのでやりたいようにやってください。
addBlogCard.css
.blog-card {
display: block;
width: 100%;
margin-bottom: 1.5rem;
padding: 1rem;
background-color: #fff;
border: 2px solid #eee;
text-decoration: none;
color: #4C4C4C;
}
.blog-card__header {
width: 100%;
display: flex;
gap: 1.5rem;
}
.blog-card__footer {
display: flex;
justify-content: space-between;
gap: .5rem;
width: 100%;
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #eee;
}
.blog-card__site {
display: flex;
align-items: center;
gap: .5rem;
font-size: 80%;
}
.blog-card__site img {
flex-shrink: 0;
margin-bottom: 0 !important;
}
.blog-card__more span {
display: inline-block;
padding: 0px 2rem;
border: 1px solid #eee;
font-size: 80%;
font-weight: bold;
}
.blog-card__thumbnail {
flex-shrink: 0;
}
.blog-card__title,
.blog-card__excerpt {
line-height: 1.7;
text-align: justify;
}
.blog-card__title {
font-weight: bold;
}
.blog-card__excerpt {
font-size: 85%;
}
@media screen and (max-width: 599px) {
.blog-card__excerpt {
display: none;
}
}
また、cssの読み込みが必要になりますので、addBlogCard.php内でフックをかけておきます。
addBlogCard.php
add_action( 'wp_enqueue_scripts', 'addBlogCardScript' );
function addBlogCardScript() {
$css = addBlogCard_get_template_url().'/addBlogCard.css';
wp_enqueue_style( 'addBlogCard_style', $css, array() );
}
ショートコードの呼び出し設定
この時点でショートコード自体は機能します。(functions.phpで呼び出せば)
ただ、下記のようにエディタから選択できるようにしておきたいので作業を続けます。
jsの処理
addBlogCard.js
tinymce.create('tinymce.plugins.blogcard', {
init: function(ed, url) {
ed.addButton('blog_card', {
title: 'ブログカード',
text: 'ブログカード',
type: 'menubutton',
menu: [
{
text: '簡易',
onclick: function () {
ed.insertContent('[blog_card url=""]');
}
},
{
text: 'カテゴリー等一覧',
onclick: function () {
ed.insertContent('[blog_card url="" tax="category ea etc" id="category_id"]');
}
},
{
text: 'フル',
onclick: function () {
ed.insertContent('[blog_card url="" title="タイトル" excerpt="説明" thumb="media_id"]');
}
}
]
});
},
createControl : function(n, cm) {
return null;
},
});
tinymce.PluginManager.add('blogcard_plugin', tinymce.plugins.blogcard);
※[]はなぜかエスケープできなかったので全角で入れていますので半角に戻してください。
説明すると長くなるので割愛しますが、TinyMCE用にblogcardというプラグインを作成しています。
また、menu
内でブログカード配下に3つのメニューを作成しています。
phpの処理
次に作成したTinyMCE用のプラグインをTinyMCEに登録していきます。
addBlogCard-tinymce.php
// 作成したプラグインを登録
add_filter( 'mce_external_plugins', 'register_mce_blogcard_plugins' );
function register_mce_blogcard_plugins( $plugin_array ) {
if(is_child_theme()) {
$js = get_stylesheet_directory_uri().'/functions/addBlogCard/addBlogCard.js';
} else {
$js = get_template_directory_uri().'/functions/addBlogCard/addBlogCard.js';
}
$plugin_array[ 'blogcard_plugin' ] = $js;
return $plugin_array;
}
// 作成したプラグインのボタンを登録
add_filter( 'mce_buttons', 'add_blogcard_buttons' );
function add_blogcard_buttons( $buttons ) {
$buttons[] = 'blog_card';
return $buttons;
}
こちらも長くなるので割愛しますが、TinyMCEに先ほど作成したプラグイン「blogcard」を登録しています。
最後にaddBlogCard-tinymce.phpをaddBlogCard.phpに呼び出せば完了です。
addBlogCard.php
require_once 'addBlogCard-tinymce.php';
実装
では、今まで作成したものを実装します。
といっても簡単で、functions.phpに1行書けば終わります。
functions.php
include 'functions/addBlogCard/addBlogCard.php';
これで実際に機能するようになります。
最後に
プラグインにすると余計な説明が増えるので、今回はfunctionsを作って対応する方法にて紹介しました。
私自身、このfunctionsに自分で作成した関数をとりためているのですが非常に便利ですので、皆さんも利用してみてください。
また、今回のポイントは下記となります。
# point
str_replace
で
を置き換えできない時は\xc2\xa0
を試してみる- ショートコード作成では
get_template_part
をそのまま使用できない - 外部ドメインのものは直リンクしないのがWEBのマナー
- 作成した関数をfunctionsフォルダにまとめておくと便利
それではよいWPライフを!