« JavaでOpenCV Main WordPressで前後の記事へのリン... »

WordPress: memolinkプラグイン作成

めもリンク用に日頃使っているperlスクリプトのlink2htmlを元にそのWPプラグインを作成してみた。perlからphpへの手動変換で似た言語ちゅーか、微妙に違う言語なんで、どちらを使ってるんだか混乱した…。プラグインの枠組みはPHP Hilight StringAmazon Linkageを参考にさせて頂きました。謝意を表しますm(__)m。

使い方は次のようになります。

 [mlink]
 リンクサンプル
   http://www.asahi.com/
     朝日新聞
   http://www.zakzak.co.jp/
    zakzak
       ||foo
     bar
   aaa
 [/mlink]

上記のように[mlink]~[/mlink]中にURLと次行に字下げしたタイトルを書いていく(上の例は各行冒頭に空白が1つ余計に入っています)と以下のような箇条書きリンクに変換されます。

リンクサンプル

きちんと変換できたかな?行頭に||があると連結表示されます。タグ名は「link」あるいは「memolink」にすることも考えたんですが、前者は他にありそうだし、後者は長すぎるということで、現在のタグに落ち着いてます。プラグイン名はmemolinkとしました。(→追記:統一するため記事タイトルもlink2htmlからmemolinkに変えました)

現在のところ、WPのビジュアルエディタとの相性が悪いようで、ビジュアルエディタで再編集しようとすると、リンク情報として重要な行頭空白が勝手に除かれて左ベタ打ちとなってしまいます。いまのところはHTMLエディタ上でご使用下さい。

現在WPで使っているlibrioのテーマはblockquoteの文字サイズが本文に比べて大きかったり、ulなどの箇条書きでの入れ子の場合のmargin-bottomが大きすぎたりしたので、スタイルシートをいくつか調整した。

プラグインのソースはこちら↓。ダウンロードはこちらを入手しpluginディレクトリに展開して下さい。

  1.  <?php
  2.  /*
  3.  Plugin Name: Memo link generator
  4.  Plugin URI: http://mibai.tec.u-ryukyu.ac.jp/~oshiro/Programs/others/
  5.  Description: URLと次行の字下げタイトルからなるリンク情報を箇条書きのリンクリストに変換します。[mlink]~[/mlink]中に記述して下さい。
  6.  Version: 0.1.1
  7.  Author: Oshiro Naoki
  8.  Author URI: http://mibai.tec.u-ryukyu.ac.jp/~oshiro/
  9.  */
  10.  
  11.  if (class_exists('MemoLink')){
  12.      new MemoLink();
  13.  }
  14.  
  15.  class MemoLink {
  16.      //classの決定
  17.      var $tpl = '<div class="memo-link" {STYLE}>{CONTENT}</div>';
  18.      var $blocks = array();
  19.  
  20.      var $indent=0;
  21.  
  22.      function first($content) {
  23.          $content = preg_replace('#(^|\n)\[mlink\](.*?)\[/mlink\]#sie', '$this->do_link2html(\'\\2\', $content);', $content);
  24.          return $content;
  25.      }
  26.  
  27.      function second($content) {
  28.          $content = str_replace(array_keys($this->blocks), array_values($this->blocks), $content);
  29.  
  30.          return $content;
  31.      }
  32.  
  33.      function __construct() {
  34.          if (function_exists('add_filter')){
  35.              add_filter('the_content', array(&$this, 'first'), -1000);
  36.              add_filter('the_content', array(&$this, 'second')1000);
  37.          }
  38.      }
  39.  
  40.      function do_link2html($txt, $content) {
  41.          $blockID = $this->getBlockID($content);
  42.  
  43.          $this->blocks[$blockID] = str_replace('{CONTENT}', $this->link2html($txt), $this->tpl);
  44.  
  45.          return $blockID;
  46.      }
  47.  
  48.      function do_blocks($txt, $content) {
  49.          $txt = str_replace(array("\\"", "\\'"), array(""", "\'"), $txt);
  50.          $blockID = $this->getBlockID($content);
  51.  
  52.          $this->blocks[$blockID] = '<div>::MEMOLINK_BLOCK_5::</div>';
  53.  
  54.          return $blockID;
  55.      }
  56.  
  57.      function getBlockID($content) {
  58.          static $num = 0;
  59.  
  60.          do {
  61.              ++$num;
  62.              $blockID = "<div>::MEMOLINK_BLOCK_$num::</div>";
  63.          } while(strpos($content, $blockID) !== false);
  64.  
  65.          return $blockID;
  66.      }
  67.  
  68.      function link2html($content) {
  69.          $spc_pre[0]=$spc="";
  70.          $item=$next_item="<li>";
  71.          $opt_t="";
  72.  
  73.          $text="";
  74.          $lines=split("\n", $content);
  75.          for ($l_no=0; $l_no<count($lines); $l_no++) {
  76.              $str=chop($lines[$l_no]);
  77.              if ($str=="") continue;
  78.              $str=str_replace('#\t#','        ',$str);
  79.              #&imgtag;
  80.  
  81.              #
  82.              # 表題処理
  83.              #
  84.              if (preg_match('#^\s*\[\d{4}/\d{2}/\d{2}\]#',$str)>0) {continue;} # 日付行は無視
  85.              if (preg_match('/^\s*#/',$str)>0) {continue;}                      # 行頭 '#'はコメントで無視
  86.              if (preg_match('/^(\s*)\|+/',$str)>0) { # 行頭が '|' なら連結表示
  87.                  $str=preg_replace('/^(\s*)\|+/','\1',$str);
  88.                  $item="||";
  89.              }
  90.              if (preg_match('/^(\s*)((ftp|telnet|https?|file|href|mailto|news|javascript):.+)(\s*)$/',$str,$arr_str)==0) {
  91.                  # URL 'http:' などでなければ
  92.                  if (preg_match('/^(\s*)(.+)\s*$/',$str,$arr_str)>0) {
  93.                      $spc=$arr_str[1];
  94.                      $label=$arr_str[2];
  95.                  }
  96.                  if (preg_match('/^\s+/',$spc)>0) { # 行頭に空白があれば
  97.                      $arr_spc=array(); # とりあえず空の配列を用意
  98.                      if ($item!="||") {$text.=$this->indent_check($spc, $spc_pre);}
  99.                      if (preg_match('/^\s*-+\s*$/',$label)>0) { # マイナス記号での横線指定の場合
  100.                          $text.="\n$spc<hr>\n";
  101.                      } else {
  102.                          if ($item!="||") $text.="\n$spc";
  103.                          $text.="$item$label";
  104.                      }
  105.                      $item=$next_item; # [1997/06/23] OSHIRO Naoki. added 1 line.
  106.                  } else {
  107.                      $text.="\n";
  108.                      $ul=""; for ($i=0; $i<$this->indent; $i++) {$ul.="</ul>";} # インデント分<ul>を閉じる
  109.                      if ($this->indent > 0) $text.="$spc_pre[1]" . $ul . "\n";
  110.                      $item="<li>"; # [1997/06/25] OSHIRO Naoki. added 1 line
  111.                      $text.="\n";
  112.                      if (preg_match('/^-+\s*/',$str)>0) {
  113.                          $text.="<hr>";
  114.                      } else  {
  115.                          if ($str!="") $text.="<b>$str</b>";
  116.                      }
  117.                      $spc_array=array();
  118.                      $this->indent=0;
  119.                  }
  120.                  continue;
  121.              }
  122.  
  123.              #
  124.              # URL (http:) 処理
  125.              #
  126.              $spc=$arr_str[1]; $url=$arr_str[2]; # URL(HTTP) 取得
  127.              if ($item!="||") $text.=$this->indent_check($spc, $spc_pre);
  128.              #last if (eof);
  129.  
  130.              # 指定ファイルがカレントディレクトリにあるならば file:,http: を除く
  131.              $url=preg_replace('#^(file|http):([^/])#','\2',$url);
  132.  
  133.              #
  134.              # ラベル処理
  135.              #
  136.              do {
  137.                  # 行頭 "#" である
  138.                  # 日付である
  139.                  # ならばラベルでない
  140.                  $str=$lines[++$l_no]; # 次の行を取得
  141.                  $str=preg_replace('#\t#','        ',$str);
  142.                  #&imgtag;
  143.              } while (preg_match('/^\s*#/',$str)>0 || preg_match('/^\s*\[\d{4}\/\d{2}\/\d{2}\]/',$str)>0); # テスト中
  144.              $keep=$str;
  145.              $next_item="<li>";
  146.              if (preg_match('/^(\s*)\|+/',$str, $arr_str)>0) { # 行頭が '|' なら連結表示
  147.                  $str=preg_match('/^(\s*)\|+/','\1',$str);
  148.                  $next_item="||";
  149.              }
  150.              if (preg_match('/^(\s*)http:/',$str)>0
  151.                  || preg_match('/^$spc\s/',$str)!=0 # add "\s" for correction. [1997/06/29]
  152.                  || ($next_item=="||")
  153.                  ) {
  154.                  # 'http:' である
  155.                  # 行頭の空白が $spc と同じ,または,より小さい
  156.                  # 行頭 "||" である
  157.                  # ならばラベルでない
  158.                  if ($item!="||") $text.="\n$spc";
  159.                  $text.="$item<a href="$url">" . basename($url) . "</a>"; # $url のベースをラベルとして表示
  160.                  if ($item!="||") $text.=$this->indent_check($spc, $spc_pre);
  161.                  $item=$next_item;
  162.                  $next_item="<li>"; # [1998/03/27]
  163.                  #next if (eof);
  164.                  #$str=$keep;
  165.                  $l_no--; continue; #redo; # 取り込んだ行を処理しなおす
  166.              }
  167.              $str=preg_replace('/^\s*(.+)\s*/','\1',$str); # ラベル取得
  168.              if ($item!="||") $text.="\n$spc";
  169.              $text.="$item<a href="$url">$str</a>";
  170.              if ($item!="||") $text.=$this->indent_check($spc, $spc_pre);
  171.              $item=$next_item;
  172.          }
  173.          $text.="\n";
  174.          $ul=""; for ($i=0; $i<$this->indent; $i++) {$ul.="</ul>";}
  175.          $text.="$ul\n";
  176.          # 最後にラベルを閉じる
  177.          $spc_pre=array();
  178.          $this->indent=0;
  179.  
  180.          return $text;
  181.      }
  182.  
  183.      function indent_check(&$spc, &$spc_pre) {
  184.          $text="";
  185.          for (;;) {
  186.              if ($spc==$spc_pre[0]) return $text; # 同じ深さなら何もしない.
  187.              if (preg_match("#^$spc_pre[0]\s+#",$spc)>0) {      # 行頭の空白を以前のものと比較して大きければ
  188.                  $text.="\n";
  189.                  $text.="$spc_pre[0]<ul>"; # <ul> を表示して
  190.                  array_unshift($spc_pre, $spc);
  191.                  $this->indent++;            # インデントレベルを上げる
  192.                  $spc=$spc_pre[0];
  193.                  return $text;
  194.              } else if ($this->indent>0) {    # そうでなく,さらにインデントレベルが正なら
  195.                  array_shift($spc_pre);
  196.                  $this->indent--;          #インデントレベルを下げ
  197.  
  198.  
  199.  
  200.                  $text.="\n";
  201.                  $text.="$spc_pre[0]</ul>"# </ul> で閉じる
  202.              }
  203.          }
  204.      }
  205.  
  206.      function imgtag($spc, $file, $label) {
  207.          # 独自の img: タグを追加 [1997/11/28] OSHIRO Naoki.
  208.          if (preg_match('/(\s*)img:(.+\.(jpg|gif))\s(.*)\s*$/',$label,$match)>0) {
  209.              chop;
  210.              $spc=$match[0]; $file=$match[1]; $label=$match[3];
  211.              if (preg_match('/^\s*$/',$label)>0) {
  212.                  $label=$file;
  213.                  $_="";
  214.              } else {
  215.                  $_=$label;
  216.          return $text;
  217.      }
  218.  
  219.      function indent_check(&$spc, &$spc_pre) {
  220.          $text="";
  221.          for (;;) {
  222.              if ($spc==$spc_pre[0]) return $text; # 同じ深さなら何もしない.
  223.              if (preg_match("#^$spc_pre[0]\s+#",$spc)>0) {      # 行頭の空白を以前のものと比較して大きければ
  224.                  $text.="\n";
  225.                  $text.="$spc_pre[0]<ul>"; # <ul> を表示して
  226.                  array_unshift($spc_pre, $spc);
  227.                  $this->indent++;            # インデントレベルを上げる
  228.                  $spc=$spc_pre[0];
  229.                  return $text;
  230.              } else if ($this->indent>0) {    # そうでなく,さらにインデントレベルが正なら
  231.                  array_shift($spc_pre);
  232.                  $this->indent--;          #インデントレベルを下げ
  233.                  $text.="\n";
  234.                  $text.="$spc_pre[0]</ul>"# </ul> で閉じる
  235.              }
  236.          }
  237.      }
  238.  
  239.      function imgtag($spc, $file, $label) {
  240.          # 独自の img: タグを追加 [1997/11/28] OSHIRO Naoki.
  241.          if (preg_match('/(\s*)img:(.+\.(jpg|gif))\s(.*)\s*$/',$label,$match)>0) {
  242.              chop;
  243.              $spc=$match[0]; $file=$match[1]; $label=$match[3];
  244.              if (preg_match('/^\s*$/',$label)>0) {
  245.                  $label=$file;
  246.                  $_="";
  247.              } else {
  248.                  $_=$label;
  249.              }
  250.              $_.="$spc<IMG SRC="$file" BORDER="0" ALT="$label">";
  251.          } else {
  252.              preg_replace('#img:(.+\.(p[pgb]m))\s#','<A HREF="\1">img:$1</A>');
  253.          }
  254.      }
  255.  
  256.      function basename($name) {
  257.          if (preg_match('#([^/]+/)\s*$#',$name,$arr_name)>0) $name=$arr_name[0];
  258.          if (preg_match('#([^/]+)(\.s?html?)?\s*$#',$name,$arr_name)>0) $name=$arr_name[0];
  259.          $name=preg_replace('/\.s?html?/','',$name);
  260.          return $name;
  261.      }
  262.  }
  263.  ?>

作った(変換した)あとで思いましたが、WP上でWiki記法が使えるならわざわざ自前で作業する必要はなかったのでは…。

やはり、探すといくつかあるようですね↓。

まぁ、今回のプラグインで日常的な書き方が使えるのでもちろんこれはこれで便利ですが(phpになってるんで、pukiwikiとかでも使えるかもしれないし―)。

Leave a comment

Your comment