HeaderImage

前回、とっても高機能な Dynamic Template を入れましたので、このプラグインでブログカードを実装しようと思います。まずは、完成品の作業状態をGIFにしたのでみてください。

①リンク先のURLをコピペで貼り付け、②選択してテンプレートを呼び出すと、③リンク先のOGP情報が読み取られて、ブログカードのHTMLに置き換わる、という簡単なステップでブログカードが追加できます。

なお、 Dynamic Template をまだインストールできていない方は、この記事で確認ください。

たのじぃの書き捨てノート
Open Live Writer へ Dynamic Template を導入
dummy

実装方法

Dynamic Templateで新しく作ったテンプレートに、以下のコードをコピペして貼り付けしてください。


 <%

    System.Net.WebClient wclnt = new System.Net.WebClient();
    wclnt.Encoding = System.Text.Encoding.UTF8;
    string html = wclnt.DownloadString(%><%_selection%><%);

    string s_title = "";
    string s_img = "";
    string s_url = "";
    string s_site_name = "";
    string s_description = "";
    string outhtml = "";

    System.Text.RegularExpressions.RegexOptions cond = System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline;

    // Search Meta-tag
    System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("<meta(.*?)>", cond);

    System.Text.RegularExpressions.MatchCollection mc = r.Matches(html);
    foreach (System.Text.RegularExpressions.Match m in mc)
    {
        // title
        System.Text.RegularExpressions.Regex r_title = new System.Text.RegularExpressions.Regex("property=[\"']og:title[\"']", cond);
        System.Text.RegularExpressions.Match m_title = r_title.Match(m.Value);
        if (m_title.Success)
        {
            System.Text.RegularExpressions.Regex r_cont = new System.Text.RegularExpressions.Regex("content=[\"'](?<cont>.*?)[\"']", cond);
            System.Text.RegularExpressions.Match m_cont = r_cont.Match(m.Value);
            s_title = m_cont.Groups["cont"].Value;
        }
        // img
        System.Text.RegularExpressions.Regex r_img = new System.Text.RegularExpressions.Regex("property=[\"']og:image[\"']", cond);
        System.Text.RegularExpressions.Match m_img = r_img.Match(m.Value);
        if (m_img.Success)
        {
            System.Text.RegularExpressions.Regex r_cont = new System.Text.RegularExpressions.Regex("content=[\"'](?<cont>.*?)[\"']", cond);
            System.Text.RegularExpressions.Match m_cont = r_cont.Match(m.Value);
            s_img = m_cont.Groups["cont"].Value;
        }
        // url
        System.Text.RegularExpressions.Regex r_url = new System.Text.RegularExpressions.Regex("property=[\"']og:url[\"']", cond);
        System.Text.RegularExpressions.Match m_url = r_url.Match(m.Value);
        if (m_url.Success)
        {
            System.Text.RegularExpressions.Regex r_cont = new System.Text.RegularExpressions.Regex("content=[\"'](?<cont>.*?)[\"']", cond);
            System.Text.RegularExpressions.Match m_cont = r_cont.Match(m.Value);
            s_url = m_cont.Groups["cont"].Value;
        }
        // site_name
        System.Text.RegularExpressions.Regex r_site_name = new System.Text.RegularExpressions.Regex("property=[\"']og:site_name[\"']", cond);
        System.Text.RegularExpressions.Match m_site_name = r_site_name.Match(m.Value);
        if (m_site_name.Success)
        {
            System.Text.RegularExpressions.Regex r_cont = new System.Text.RegularExpressions.Regex("content=[\"'](?<cont>.*?)[\"']", cond);
            System.Text.RegularExpressions.Match m_cont = r_cont.Match(m.Value);
            s_site_name = m_cont.Groups["cont"].Value;
        }
        // description
        System.Text.RegularExpressions.Regex r_description = new System.Text.RegularExpressions.Regex("property=[\"']og:description[\"']", cond);
        System.Text.RegularExpressions.Match m_description = r_description.Match(m.Value);
        if (m_description.Success)
        {
            System.Text.RegularExpressions.Regex r_cont = new System.Text.RegularExpressions.Regex("content=[\"'](?<cont>.*?)[\"']", cond);
            System.Text.RegularExpressions.Match m_cont = r_cont.Match(m.Value);
            s_description = m_cont.Groups["cont"].Value;
        }
    }

    outhtml += "<div class=\"bcard-wrapper\">";
    outhtml += "<span class=\"bcard-main withogimg\">";
    outhtml += "<span class=\"bcard-header withgfav\">"; 
    outhtml += "<div class=\"bcard-favicon\" style=\"background-image: url(&quot;";
    outhtml += "https://www.google.com/s2/favicons?domain=" + s_url + "&quot;);\"></div>";
    outhtml += "<div class=\"bcard-site\">"+ s_site_name + "</div>";
    outhtml += "</span>";
    outhtml += "<div class=\"bcard-title\">" + s_title + "</div>";
    outhtml += "<div class=\"bcard-description\">" + s_description + "</div>";
    outhtml += "<div class=\"bcard-img\" style=\"background-image:url(&quot;";
    outhtml += s_img + "&quot;);\"></div>";
    outhtml += "</span>";
    outhtml += "<a href=\"" + s_url + "\">dummy</a></div>";

%>
<%= outhtml %>

追記(2021/03/05)

OpenLiveWriterでダウンロードしてから編集する場合、ダウンロード後のHTML整形時に innertext がない a タグが消されてしまう現象がありました。この対策のため、a タグに ”dummy” とテキストを挿入しています。

別タブで開くリンクにするには、outhtml へ書き出している最終行を以下に変更してください。私は二つのテンプレートを使い分けるようにしました。


outhtml += "<a href=\"" + s_url + "\" target=\"_blank\" rel=\"noopener noreferrer\">dummy</a></div>";

CSSは、次のように設定しています。お好みで弄っちゃってください。なお、記事一覧で採用した、カード全体でリンクする方式を使ってます。


  /****************************************
    ブログカードジェネレータCSS
  *****************************************/
  .bcard-wrapper{
    display: block;
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    margin-top: 1.5em;
    margin-bottom: 1.5em;
    border-radius: 7px;
    padding: 6px 9px 6px 9px;
    border: 2px solid var(--background-base-color);
    box-shadow: 10px 10px 15px -10px var(--font-color);
    background-color: ghostwhite;
    position:relative;
    z-index:1;
  }
  .bcard-wrapper:hover {
    box-shadow: 10px 10px 15px -10px darkred;
    background: powderblue;
    transform: translate(-0.1em,-0.1em);
  }
  .bcard-wrapper >a{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    text-indent: -999px;
    z-index: 2;
  }
  .bcard-site,.bcard-url{
    font-size: 12px;
    line-height: 1.3;
    overflow: hidden;
    max-height: 15px;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
  }
  .bcard-header {
    position: relative;
    height: 16px;
    display: block;
  }
  .withgfav{
    margin: 0.1em 0.1em 0.3em 0.1em;
    padding: 2px 23px 2px 23px;
  }
  .bcard-favicon {position: absolute;
    top: 0px; left:0px; width:16px; height:16px;}
  .bcard-main{
    overflow: hidden;
    position: relative;
    display: block;
  }
  .withogimg{
    padding-right: 170px;
    height: 134px;
  }
  .bcard-img {
    width: 165px;
    height: 134px; 
    position: absolute;
    top: 0;
    right: 0;
    background-size:cover;
    background-position:center center;
  }
  .bcard-title{
    font-size: 20px;
    margin: 0 0 2px;
    line-height: 1.4;
    
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    font-weight: bold;
  }
  .bcard-description {
    line-height: 1.5;
    font-size: 12px;
    max-height: 72px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
  }
  .bcard-title a{
	color:#424242!important;
  	text-decoration:none!important;
  }
  .bcard-url a{color:#9e9e9e;}
  .bcard-title a:hover,.bcard-url a:hover,.bcard-site a:hover{text-decoration:underline;}

使用上の注意点

Sourceタブ上のほうが使いやすいです

参考GIFでは、わかりやすいようにSourceタブ上で変換しましたが、Editタブ上だとリンク先コピペ時にリンクがくっついてきます。リンクがくっついたままだと、上手く動作しません。タグごと引き渡してしまうため、リンク先からOGP情報をひっぱってこられずエラーになります。コード側で分離するとかは、めんどくさいので実装しませんでした。Editタブ上で使う場合は、貼り付け後に、リンクを切るひと手間が必要です。なお、リンクを右クリックして [Remove hyperlink] でリンクを切ることができます。

OGP情報のないリンク先では使えない

もちろんですが、OGP情報がないリンク先は真っ白な箱だけリンクになってしまいます。

自動更新とかはされない

このテンプレ動作させた時にOGP情報を取りに行ってるので、後々にリンク先が変わっても更新されたりはしません。

遅かったり、危なかったり、するかも

リンク先を全読み取りして、OGP情報を検索しているだけなので、リンク先が重たかったりすると重いし、危険なスクリプトとかに弱かったりするかもしれません。そういうところは自己責任でお願いします。