Wed
29
Mar
2023
このブログカードの実装もつい2,3年前だったかと思うのですが、色々と見直している中で今回はPHP内のAPIで外部リンクを取得してというのを取りやめることにしました。実はここに辿り着く前に、随分と回り道をしたのですが(DOMを使った手法を見てみたり、今更ですがスクレイピングを確認してみたりと1,2週間ハマっていました。。。
結局なのですが、どれも上手くいかず(動作が重すぎて将来性がない!など)、色々とみていたら、今時はこんなコードを記述しなくてもブログカードに必要な情報を取得できるブックマークレットによる方法があるということが、最終的に分かりました(世の中は既にこんな便利な機能がとっくにあるということを、初めて知りました…)。
目 次
はてなブログカードなどの情報
一つはお馴染みなのですが、大変お世話になっている寝ログの下記サイトで勉強させてもらいましたが、はてなブログやその他ブラウザツールとして、一発で!ブログカードとしての情報が取得できるものが既にあるとのことです。
つくづく自身の情報が周回遅れだと痛感してしまいます。ただ、はてなブログカードは機能としては必要十分で見た目も奇麗なのですが、iframeが使われている点、カスタマイズできない点、将来的にはてなに依存してしまうというリスクがあるとのことです。
ブックマークレットを利用した方法
あったので、どうしたものかと考えていたところ、下記のサイトで独自にブックマークレットを使用したOGP情報の取得スクリプトを公開されている方がいました。
上記のサイトのカードはまさにiframeの懸念を解消してくれるものだったのですが、faviconが取得できない点と幾つかのサイトで動かないという事象がありました。推測するに下記サイトにあるようなCSPと呼ばれるセキュリティのためかと思われます(でも最終的にはコードを変更すると動いたので多分違うかも知れません)。
せっかく見つけたiframeなしのブックマークレット用スクリプトでしたが、結構な頻度で稼働しないサイトが多いので、ちょっと実用的には難しいかなと思っていたところ、似たようにiframeを使わずに実装できるブックマークレットを公開されている方のサイトを見つけました。
こちらの方のサイトのスクリプトは最初に見つけたサイトでは実装していなかったファビコン取得のコードも含まれており、本当に言うことない!内容で本当にありがとうございます。ただ、実際には上記サイトのままだと最初は稼働しなかったので、最初のサイトの方のコードと見比べてみて、下記の箇所だけ入れ替えると問題なく稼働しました!
s.src=“//j.mp/1bPoAXq”;
下記に変更
s.src = ‘//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js’;
こちらのサイトのスクリプトですと、理由は待ったく不明なのですが、最初の方のスクリプトで稼働しなかったサイトも問題なく動くようで、こちらであれば実用的にも問題なさそうです。
ブックマークレットのタグ取得の問題点
ただ、出力コードを生のタグで取得して記事に貼り付けると、下記サイトにあるようにWordPressの仕様としてタグが勝手に改変されるという現象が起きてしまいます。
もちろん、上記事象に対する対策も巷に溢れているのですが、そうするとこの先のメンテも大変になるのと、タグをそのまま貼り付けると下書きの記事の表示がとんでもなくにぎやかになってしまう(下記の例)ということもあります。
ブックマークレットでショートコードを取得する方法
そこで、タグで取得するのではなく、ショートコードで取得してショートコードをPHPで変換するということにしました。実際に記事に貼り付ける作業はタグかショートコードかの違いしかありませんので、記事編集の手間は変わりません。ショートコードとすることで、その時点で追記や修正ができるというメリットもあるかと思います。
ということで、下記のようなステップのブログカードに改変することができました!
ブックマークレットでショートコードを取得(JavaScript)※記事内にはこれをペースト
ショートコードから出力用のタグを取得(PHP)※従来通りfunction.phpにて出力
従来の方法もショートコードを挿入してそこにURLをコピペでしたので、コピペ回数の手順としては変わらないと思います。(ブックマークレットのボタンを押す手間は、記事内へショートコードを挿入する手順と相殺ということで、結局同じでしょうか。)外部リンクと内部リンクで従来のカードと今回のカードの比較は、下記のような感じになります。
外部リンク(従来のカード)
外部リンク(今回のカード)
内部リンク(従来のカード)
内部リンク(今回のカード)
外見のデザインは下記サイトの方のcssが奇麗でしたので、全面的に参考にさせていただきました。ありがとうございます。
投稿IDをショートコードとしてJavaScriptで取り込む部分は、下記サイトの方のコードを参考にさせていただきました。ただ、最終的にはその先(ショートコードの投稿IDをPHPで変換するなど)が私の知識不足でうまく活用できず、最終的にはURLから投稿IDを取得する方法にしています。
今回作成したコード類
ほとんど上記の方々のサイトからの引用でしか作成されていませんが、一応参考までに最終的に実装したコード類を下記にメモしておきます。
ブックマークレット用JavaScript
- // ブックマークレット:ショートコード出力用
- javascript: (function() {
- (function(d, f, s) {
- s = d.createElement(“script”);
- s.src = ‘//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js’;
- s.onload = function() {
- f(jQuery.noConflict(!0))
- };
- d.body.appendChild(s)
- })(document, function($) {
- var obj = [];
- // obj.title = $(‘title’).text(); //タイトル
- obj.title = $(‘meta[property=”og:title”]’).attr(‘content’); //タイトル
- obj.img = $(‘meta[property=”og:image”]’).attr(‘content’); //アイキャッチ画像
- // 上記タグで取得できない場合
- if(obj.img == undefined){
- obj.img = ‘https://picsum.photos/160/120/?random’; //ランダム画像を表示
- }
- obj.desc = $(‘meta[name=”description”]’).attr(‘content’); //サイト概要
- // 上記タグで取得できない場合
- if(obj.desc == undefined){
- obj.desc = $(‘meta[property=”og:description”]’).attr(‘content’); //サイト概要
- }
- obj.sitename = $(‘meta[property=”og:site_name”]’).attr(‘content’); //サイト名
- // obj.key = $(‘meta[name=”keywords”]’).attr(‘content’); //キーワード
- obj.url = document.URL; //URL
- obj.dsurl = $(‘meta[property=”og:url”]’).attr(‘content’); //表示用URL
- obj.domain = location.host; //ドメイン名
- // —————————————————–
- let strdesc; //obj.descを文字列型とする変数
- strdesc = new String(obj.desc); //obj.descを文字列型に変換
- var objdescSt = strdesc.substr( 0, 60 ); //文字数を制限して取得
- // —————————————————–
- const classArray = Array.from(document.body.classList); // WordPressの投稿IDとページIDを取得
- const postId = classArray.filter((c) => c.startsWith(‘postid-‘)).toString().slice(7);
- const pageId = classArray.filter((c) => c.startsWith(‘page-id-‘)).toString().slice(8);
- // ショートコードの出力
- var Stcard = ‘[sc_blogcardJS url="' + obj.url + '" title="' + obj.title + '" excerpt="' + objdescSt + '…' +
- '" sitename="' + obj.sitename + '" img="' + obj.img + '" domain="' + obj.domain + '" dsurl="' + obj.dsurl +
- '" postId="' + postId + '" pageId="' + pageId + '"]‘;
- prompt(‘ブログカードのShortCodeを生成しました。’, Stcard);})})();
今回は、結構な工数(ほとんどサイトを探してトライ&エラーしているだけですが)を使ってしまいましたが、結果的にはしばらくは使えそうなブログカードの手段を見つけることができました!
ちなみに上記のJavaScriptのコードをブックマークレット化するのは、下記サイトで”ファイル先頭のコメントは残す”のチェックを外して成形するだけで、問題なくできました。
ただ、下記のサイトのように自動でブックマークレット化のリンクまで生成してくれるサイトもあります。
一応、コピペするだけの状態にしたコードのテキストを下記に記載しておきます。
- javascript:(function(){(function(d,f,s){s=d.createElement(“script”);s.src=‘//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js’;s.onload=function(){f(jQuery.noConflict(!0))};d.body.appendChild(s)})(document,function($){var obj=[];obj.title=$(‘meta[property=”og:title”]’).attr(‘content’);obj.img=$(‘meta[property=”og:image”]’).attr(‘content’);if(obj.img==undefined){obj.img=‘https://picsum.photos/160/120/?random’;}obj.desc=$(‘meta[name=”description”]’).attr(‘content’);if(obj.desc==undefined){obj.desc=$(‘meta[property=”og:description”]’).attr(‘content’);}obj.sitename=$(‘meta[property=”og:site_name”]’).attr(‘content’);obj.url=document.URL;obj.dsurl=$(‘meta[property=”og:url”]’).attr(‘content’);obj.domain=location.host;let strdesc;strdesc=new String(obj.desc);var objdescSt=strdesc.substr(0,60);const classArray=Array.from(document.body.classList);const postId=classArray.filter((c)=>c.startsWith(‘postid-‘)).toString().slice(7);const pageId=classArray.filter((c)=>c.startsWith(‘page-id-‘)).toString().slice(8);var Stcard=‘[sc_blogcardJS url="'+obj.url+'" title="'+obj.title+'" excerpt="'+objdescSt+'…'+'" sitename="'+obj.sitename+'" img="'+obj.img+'" domain="'+obj.domain+'" dsurl="'+obj.dsurl+'" postId="'+postId+'" pageId="'+pageId+'"]‘;prompt(‘ブログカードのShortCodeを生成しました。’,Stcard);})})();
ショートコードをブログカードに変換するPHP
このショートコードを投稿記事内に貼り付ければOKという形にしたいため、ショートコードを読み込んでブログカードとして出力するコードをPHPでfunction.phpに記述します。これは既に前から作成していたブログカードを改造して作成してみました。実際に使っているコードは内部リンクの場合は、投稿IDを使って別コードから取得するView数などを入れ込んでいます(下記のサンプルではコメントアウトしています)。
- // ———————————————
- // ブックマークレットで取得したショートコードからブログカードを作成
- // ———————————————-
- function show_blogcardJS($atts) {
- extract(shortcode_atts(array(
- ‘url’=>“”,
- ‘title’=>“”,
- ‘excerpt’=>“”,
- ‘sitename’=>“”,
- ‘img’=>“”,
- ‘domain’=>“”,
- ‘dsurl’=>“”
- // ‘postId’=>””,
- // ‘pageID’=>””
- ),$atts));
- // 内部リンクか外部リンクの判定
- $homedmain = wp_parse_url( home_url(), PHP_URL_HOST );
- // 内部リンクの場合
- if($domain == $homedmain){
- $cssjdge = “inblg”; //内部リンククラス追加
- $dmbudge = “関連する記事”; //バッジ表示
- $tempurl = get_template_directory_uri();
- $favicon = $tempurl.‘/images/favicon.ico”‘; //ファビコン取得
- $id = url_to_postid($url); // URLから投稿IDを取得
- $siteinfo = get_bloginfo( ‘name’ ); // サイト情報
- // $postcat = get_the_category($id); //カテゴリ取得
- // $catname = $postcat[0]->name; //カテゴリ表示
- // $sitename = get_bloginfo( ‘name’ ); // サイト名
- // $postview = getPostViews($id); // アクセス数
- // $postdate = get_the_date(‘Y年n月j日’, $id); // 投稿日
- // $siteinfo = $sitename.'<span class=”article-date”><i class=”far fa-clock”></i><time>’. $postdate .'</time></span>
- // <span class=”view-count”>’. $postview .'</span>’;
- // 外部リンクの場合
- } else {
- $cssjdge = “ex”; //外部リンククラス追加
- $dmbudge = $domain; //バッジ表示
- $favicon = ‘https://www.google.com/s2/favicons?domain=’.$url; //ファビコン取得
- $siteinfo = $dsurl .‘ | ‘. $sitename; // サイト情報
- }
- // var_dump($catname); // デバッグ用
- // ブログカードタグ出力
- $sc_Linkcard .=‘
- <div id=”blogcard” class=”blogcard ‘. $cssjdge .‘”>
- <a href=”‘. $url .‘” target=”_blank”>
- <div class=”blogcard_thumbnail”><img src=”‘. $img .‘” alt=””><span class=”cat-data”>’. $catname .‘</span></div>
- <div class=”blogcard_domain”>’. $dmbudge .‘</div>
- <div class=”blogcard_content”>
- <div class=”blogcard_title”>’. $title .‘</div><div class=”blogcard_excerpt”>’. $excerpt .‘…</div>
- <div class=”blogcard_link”><img class=”favicon” src=”‘. $favicon .‘” alt=””>’. $siteinfo .‘</div>
- </div>
- <div class=”clear”></div>
- </a>
- </div>’;
- return $sc_Linkcard;
- }
- //ショートコードに追加
- add_shortcode(“sc_blogcardJS”, “show_blogcardJS”);
こちらも特にオリジナルではなく、色々な方のサイトから参考にさせてもらって改造したものですので、念のため。こちらをfunction.phpにペーストすれば稼働するとは思いますが、すみませんが私自身では何もサポートはできません。
外観を整えるcssコード
最後はcssです。以前から使っているブログカードのcssに追記する形で作っています。
- /* ========================================================================================= */
- /* ブログカード*/
- /* ========================================================================================= */
- /* ブログカード(内部リンク用)*/
- div#blogcard {
- position: relative;
- border-radius: 5px;
- border: 1px solid #eeeeee;
- word-wrap: break-word;
- margin: 30px 40px;
- box-shadow: 0 0 10px 6px rgba(0,0,0,.025);
- display: block;
- min-height: 8rem;
- }
- /* ブログカード(外部URL用)*/
- div#blogcard.ex {
- background-color: #f7f7f7;
- }
- /* ブログカード(内部リンク用)*/
- div#blogcard.inblg {
- background-color: #F4F9FD;
- }
- /* ブログカード(Booking.com-URL用)*/
- div#blogcard.bkg {
- background-color: rgba(0,53,128,0.85);
- }
- /* ブログカード:概要説明 */
- div#blogcard > a > div.blogcard_content {
- line-height: 0;
- font-size:inherit;
- letter-spacing: 0;
- }
- /* ブログカード背景色:内部リンク */
- div#blogcard div.blogcard.inblg {
- background-color: #F4F9FD;
- }
- div#blogcard a,
- div#blogcard a a:visited {
- color:inherit;
- text-decoration: none;
- opacity: 1;
- transition: all 0.2s ease;
- }
- div#blogcard a:hover {
- opacity: 0.6;
- color: #0270BE;
- }
- /* サムネイル画像 */
- div#blogcard div.blogcard_thumbnail {
- float: left;
- padding: 15px;
- }
- /* タイトル */
- div#blogcard div.blogcard_title {
- font-size: 1em;
- font-weight: bold;
- line-height: 1.4;
- padding: 15px 20px 5px;
- min-height: 3.5rem;
- }
- /* ブログカード(Booking.com-URL用)*/
- div#blogcard.bkg div.blogcard_title {
- color: #fff;
- padding: 17px 20px 5px 0;
- min-height: 4.5rem;
- }
- /* 概要文 */
- div#blogcard div.blogcard_excerpt {
- font-size: 0.75em;
- line-height: 1.4;
- padding: 0 17px 5px 20px;
- min-height: 2.5rem;
- }
- /* ブログカード(Booking.com-URL用)*/
- div#blogcard.bkg div.blogcard_excerpt {
- font-size: 0.8em;
- line-height: 1.1;
- padding: 0 17px 5px 20px;
- color: #ccc;
- min-height: 2.5rem;
- }
- div#blogcard div.blogcard_link {
- font-size:0.65em;
- padding:0 17px 15px 20px;
- text-align: left;
- height: auto;
- }
- /* ブログカード(Booking.com-URL用)*/
- div#blogcard.bkg div.blogcard_link {
- background-color: #fff;
- font-size: 1rem;
- padding: 0 10px 0 0;
- text-align: right;
- min-height: 3rem;
- }
- div#blogcard.bkg div.blogcard_link > img {
- padding: 10px 0 0 0;
- }
- div#blogcard div.blogcard_link .favicon {
- margin-bottom: -4px;
- margin-right: 5px;
- }
- div#blogcard div.blogcard_date {
- margin-bottom: -4px;
- }
- /*サムネイル:外接トリミング*/
- div#blogcard div.blogcard_thumbnail img,
- div#blogcard div.blogcard_content img.thumbnail-in {
- width: 170px;/*original 240px;*/
- height:110px;/*original 160px*/
- object-fit: cover;
- }
- /*サムネイル:外接トリミング*/
- div#blogcard div.blogcard_link > img.favicon-in,
- div#blogcard.inblg div.blogcard_link .favicon {
- width: 18px;/*original 240px;*/
- height: 18px;/*original 160px*/
- object-fit: cover;
- }
- div#blogcard div.blogcard_link .icon-external-link-alt::before {
- font-size:0.75em;
- }
- span.site_title-in {
- font-size: 0.75rem;
- font-weight: bold;
- position: absolute;
- color:#163957;
- padding: 0 5px;
- }
- div#blogcard.inblg div.blogcard_link {
- font-size: 0.75rem;
- font-weight: bold;
- /* position: absolute; */
- color:#163957;
- padding: 0 5px;
- }
- /* ========================================================================================= */
- /* ブログカード;ブックマークレット対応バージョンの追加*/
- /* ========================================================================================= */
- /*ブログカードのタイトル*/
- .blogcard .heading a{
- color:#524742;/*文字カラー*/
- font-size:20px;
- margin-left:10px;
- margin-right:10px;
- }
- /*ホバー時のエフェクト*/
- .blogcard:hover{
- transition-duration:0.2s;
- background:#F2F0E9;/*背景色*/
- -webkit-transform: translateY(-3px); /*浮かす*/
- -ms-transform: translateY(-3px); /*浮かす*/
- transform: translateY(-3px); /*浮かす*/
- box-shadow: 5px 5px 13px 2px rgb(0 0 0 / 10%);/*浮いた時の影*/
- }
- /*ドメインバッジ*/
- div#blogcard .blogcard_domain{
- position: absolute;
- font-size: 0.7rem;
- padding: 0 0.5em;
- background-color:#3e62ad;/*背景色*/
- transform: translateY(-50%) translateX(2.3em);
- color:#fff;/*文字カラー*/
- border-radius: 0px ;
- }
- div#blogcard.ex .blogcard_domain{
- background-color:#464646;/*背景色*/
- }
- div#blogcard.inblg .blogcard_domain{
- background-color:#3e62ad;/*背景色*/
- }
- /*ドメインバッジのアイコン:外部リンク用*/
- div#blogcard.ex .blogcard_domain::before{
- font-family: ‘Font Awesome 5 Free’;
- font-weight: 900;
- content: ‘\f0c1’;
- margin-right: 2px;
- }
- /*ドメインバッジのアイコン:内部リンク用*/
- div#blogcard.inblg .blogcard_domain::before{
- font-family: ‘Font Awesome 5 Free’;
- font-weight: 900;
- content: ‘\f00c’;
- margin-right: 2px;
- }
- /* 内部リンク:カテゴリ表示 */
- div#blogcard.inblg .cat-data {
- font-size: .6rem;
- position: absolute;
- bottom: 1px;
- left: 15px;
- padding: 0.2rem 0.3rem;
- color: #fff;
- background-color: rgb(88,122,160,.6);
- }
- /* 内部リンク;投稿日表示 */
- #blogcard.inblg span.article-date {
- font-size: .75rem;
- color: #888888;
- margin-left: 3px;
- font-weight: normal;
- }
- /* 内部リンク:投稿日時表示 */
- #blogcard.inblg div.blogcard_link time {
- margin-left: 2px;
- }
- /* =========================================== */
- /* スマホ表示用:画面幅599pxには全て適用 */
- /* ============================================ */
- @media(max-width: 599px) {
- html {
- font-size: 15px;
- }
- .header-inner,
- .container,
- .footer-inner {
- padding: .8rem;
- }
- header#masthead hgroup{
- height: 80px;
- }
- .contents {
- margin-bottom: 1rem;
- }
- .article-list .datetime{
- display: none;
- }
- /* ——————————————————— */
- /* ブログカード */
- /* ——————————————————— */
- div#blogcard {
- margin: 10px 0;
- }
- div#blogcard .blogcard_thumbnail img,
- div#blogcard .blogcard img.thumbnail-in {
- width: 90px;
- height: auto;
- }
- div#blogcard .blogcard_title {
- font-size: 0.95em;
- padding-bottom: 17px;
- }
- div#blogcard .blogcard_excerpt {
- display: none;
- }
- div#blogcard div.blogcard_thumbnail img {
- width: 105px;
- height: 70px;
- }
- div#blogcard.inblg .cat-data {
- bottom:auto;
- }
- div#blogcard div.blogcard_title {
- font-size: 0.9em;
- }
- div#blogcard div.blogcard_link {
- display: none;
- }
- } /*=================================スマホ表示用終わり
最後に~今回のブログカードのコードの公開について
ということで、ブログカードを改訂することができました。ただ、今回の改定はタグ出力のコード(の元になる内容をショートコード)を取得ものですので、従前の都度毎にAPIで読みにいくコードより描画等は早くなったものの、リンク先が更新された時などは内容が反映されないという仕様になります。
ここら辺は下記の方のサイトに解説されています。ちなみにこちらの方のサイトの内容で、ショートコードで取得するブログカードは十分素晴らしいものが出来ると思われます(一点だけデメリットとして挙げられている”htmlが出て来るので編集画面が煩雑になる”ところだけが、改善されているとは言えますが)。
今回に限らず過去のサイトの改造はほぼ色々な方のサイトを参考にさせてもらってものですので、あまりコード等は公開していなかったのですが、今回は自身でも苦労した点が参考になるかも知れないと思いましたので、公開させていただきました。コードについては素人ですので質問されても適切に回答できませんが、同じように苦労されている方の一助になれば幸いです。また、色々と参考にさせていただいたサイト様には改めてお礼申し上げます。
コメントはお気軽にどうぞ