CocoaSpace

Drupalでウェブサイト構築

Viewsの月別アーカイブの日本語化 & WordPressのようなURLにするカスタマイズ

Jan 30 2010
Drupalバージョン: 
モジュール: 

Views 2(今回使用したのはViews 6.x-2.8)にデフォルトで設定されているarchive viewを有効にすると、WordPressやMovableTypeなどの典型的なブログCMSのように、投稿の月別アーカイブブロックをサイドバーに表示できます。特にDrupalをブログとして活用されている方にとっては重宝しそうな機能です。でも実際にarchive viewをサイドバーに表示すると、なんか変ですよね。最近の月から順に表示させたいのに古い月から表示されていたり、日本語トランスレーションを使用しているサイトでは、1月 2010というように中途半端な日本語訳になっていたりと...。

インターネットで検索していたら、ちょっと力技っぽいところもありますが、解決法がありました。CocoaSpaceの他サイトで試したところ、今のところうまくいってます。しかし、もしもここでの設定を試してみたいという方がいらっしゃいましたら、念入りにテストしてからライブサイトに採用するかを決定してください。何しろ私のような素人がやっている方法ですので、DrupalのAPIやPHPに詳しい方、より良い方法や改善すべき点などご存知でしたらコメントをお願いいたします。

ここではViews 6.x-2.8の"archive"で次のことを実現します。

  1. ブロック表示で最近の月から順に表示するように修正
  2. 1月 2010という表示を2010年1月に変更
  3. アーカイブページのURLをexample.com/archive/201001から..2010/01に変更
  4. アーカイブブロックのリンクのURLもexample.com/archive/201001から..2010/01に変更
  5. 結果的に年別のアーカイブやアーカイブのトップページも表示可能

ブロック表示で最近の月から順に表示するように修正

ブロックだけ古いほうから順に表示されています。また、1月 2010など日本語化が中途半端です。ブロックだけ古いほうから順に表示されています。また、1月 2010など日本語化が中途半端です。

まず、上の画像のようにブロック表示だけ古い年月が上位になっているのを修正します。Viewsでは通常投稿日による並び替えにSort criteriaという項目を調整すると思います。しかし、このarchiveでは既にSort Criteriaが既に降順に設定されています。実は今回のケースではArgumentsの項目を修正する必要があります。

ブロック表示のArguments -> "Action to take if argument is not present:"のラジオボタンで"Summary, sorted ascending"にチェックが入っている(これがブロック表示で古い月が上位に表示されていた原因)のを"Summary, sorted descending"に変更するだけで完了です。

1月 2010という表示を2010年1月に変更

viewsディレクトリ内のmodules/node/views_handler_argument_dates_various.incファイルに書かれている、日付のアーギュメントのhandlerをオーバーライドして、管理画面の『日付と時刻』(admin/settings/date-time)というページで設定する『日付の表示形式[カスタム](長)』の設定を利用するようにします。下のコードは、『日付の表示形式[カスタム](長)』が"Y年n月"(クォーテーションは含まない)で始まるように設定してあることを前提に書いています。

CocoaSpaceでは、日付の表示形式[カスタム](長)をこのように設定しました。CocoaSpaceでは、日付の表示形式[カスタム](長)をこのように設定しました。

参考ページ:
Link to "faces" in OG's members count column in Views should be configurable | drupal.org

まず、views_handler_argument_dates_various.incファイルの代わりとなるhandlerを作成します。ご自分のモジュールのディレクトリ内にincludesディレクトリを作成し、そのincludesディレクトリ内にMODULENAME_handler_argument_dates_various.incというファイルを作成し、下のコードを書き入れます。MODULENAMEのところはご自分のモジュール名に変更してください。

*カスタムモジュールの作成法は『シンプルなカスタムモジュールの作成』をご参照ください。

includes/MODULENAME_handler_argument_dates_various.inc

<?php
/**
 * Argument handler for a year (CCYY)
 */
class MODULENAME_handler_argument_node_created_year extends views_handler_argument_date {
  /**
   * Constructor implementation
   */
  function construct() {
    parent::construct();
    $this->arg_format = 'Y';
    $this->formula = views_date_sql_extract('YEAR', "***table***.$this->real_field");
  }

  /**
   * Provide a link to the next level of the view
   */
  function summary_name($data) {
    global $language;
    $created = $data->{$this->name_alias};
    if ($language->language == 'ja') {
      return substr(format_date(strtotime($created. "05". "15"), 'large'), 0, 7);
    }
    else {
      return strftime("%Y", strtotime($created. "05". "15"));
    }
  }
}

/**
 * Argument handler for a year plus month (CCYYMM)
 */
class MODULENAME_handler_argument_node_created_year_month extends views_handler_argument_date {
  /**
   * Constructor implementation
   */
  function construct() {
    parent::construct();
    $this->format = 'F Y';
    $this->arg_format = 'Ym';
    $this->formula = views_date_sql_format($this->arg_format, "***table***.$this->real_field");
  }

  /**
   * Provide a link to the next level of the view
   */
  function summary_name($data) {
    global $language;
    $created = $data->{$this->name_alias};
    $month = strftime("%m", strtotime($created. "05"));
    if ($language->language == 'ja') {
      if (preg_match('/^0/', $month)) {
    return substr(format_date(strtotime($created . "15"), 'large'), 0, 11);
      }
      else {
    return substr(format_date(strtotime($created . "15"), 'large'), 0, 12);
      }
    }
    else {
      return format_date(strtotime($created . "15"), 'custom', $this->format, 0);
    }
  }

  /**
   * Provide a link to the next level of the view
   */
  function title() {
    return format_date(strtotime($this->argument . "15"), 'custom', $this->format, 0);
  }
}
このコードは私が乏しい知識で書いたものですので、間違いをご指摘いただければ幸いです。

次に、MODULENAME.moduleファイルに下のコードを追加します。これで今回利用するViewsのAPIが利用可能となります。

MODULENAME.module

/**
* Implementation of hook_views_api().
*/
function MODULENAME_views_api() {
  return array(
    'api' => 2,
  );
}

更に、モジュールのディレクトリ(.info、.moduleファイルなどと同じ階層)にMODULENAME_views.incというファイルを作成します。ここでhook_views_handlers()に先程作成した代わりとなるカスタムhandlerを登録し、hook_views_data_alter()でViewsに今回作成したhandlerのほうを参照してもらうようにします。

MODULENAME_views.inc

<?php
// $Id$

/**
* @file
* Defines Custom Views data and plugins.
*
*/

/**
* Implementation of hook_views_handlers() to register all of the basic handlers
* views uses.
*/
function MODULENAME_views_handlers() {
  return array(
    'info' => array(
      'path' => drupal_get_path('module', 'MODULENAME') .'/includes',
    ),
    'handlers' => array(
      'MODULENAME_handler_argument_node_created_year' => array(
    'file' => 'MODULENAME_handler_argument_dates_various.inc',
    'parent' => 'views_handler_argument_date',
      ),
      'MODULENAME_handler_argument_node_created_year_month' => array(
    'file' => 'MODULENAME_handler_argument_dates_various.inc',
    'parent' => 'views_handler_argument_date',
      ),
    ),
  );
}


/**
* Implementation of hook_views_data_alter().
*/
function MODULENAME_views_data_alter(&$data) {
  $data['node']['created_year']['argument']['handler'] = 'MODULENAME_handler_argument_node_created_year';
  $data['node']['created_year_month']['argument']['handler'] = 'MODULENAME_handler_argument_node_created_year_month';
}

念のためにモジュールディレクトリ内のファイルのアップロード場所を図で確認してください。

カスタムモジュールのディレクトリ内のファイルの位置カスタムモジュールのディレクトリ内のファイルの位置

キャッシュをクリアしてから、archiveブロックを確認してください。2010年1月という表示になりましたか?

アーカイブページのURLをexample.com/archive/201001から..2010/01に変更

これは好みの問題かも知れませんが、archiveの月別表示のURLを201001から2010/01というWordPressなどで見慣れたURLに変更するための変更を加えたいと思います。次のページが参考になりました。

参考ページ:
Creating a WordPress like Archive with Drupal | Tessa Bakker

admin/build/views/edit/archiveに移動し、Page表示のタブをクリックしてArgumentsの部分を以下のように設定します。上記のページを参考に自分の好みの日本語表示に変更しました。

STEP 1. Node: Created year + month の除去

STEP 2. Node: Created year を追加

ページviewのArguments: Created yearの設定ページviewのArguments: Created yearの設定

  • 2-1. Title: アーカイブ: %1年
  • 2-2. Action to take if argument is not present: Summary, sorted descending

STEP 3. ノード: Created month を追加

ページviewのArguments: Created monthの設定ページviewのArguments: Created monthの設定

  • 3-1. Title: アーカイブ: %1年%2
  • 3-2. Breadcrumb: %1年
  • 3-3. Action to take if argument is not present: Summary, sorted descending

上記の変更でarchive/2010/01などの月別のアーカイブだけではなく、archive/2010などの年別のアーカイブも表示できるようになります。この設定ではデフォルトのarchive/201001からarchive/2010/01というようにスラッシュが1つ余計に入っています。ところがブロック表示のリンクは依然としてarchive/201001のフォーマットです。上記の参考サイトのコードを参考に、スラッシュが一つ余計に入るように操作します。

アーカイブブロックのリンクのURLもexample.com/archive/201001から..2010/01に変更

このURLの操作がarchiveのブロックだけに適用され、その他のviewにまで影響を与えないように、function THEMENAME_preprocess_views_view_summary()ではなく、より的を絞ったfunction THEMENAME_preprocess_views_view_summary__archive__block()を使用したいところです。しかし、これを使用するにはviews-view-summary--archive--block.tpl.phpというテンプレートが存在していなければなりません。CocoaSpaceではviews/theme/views-view-summary.tpl.phpを、使用するテーマのディレクトリ(sites/all/themes/THEMENAMEなど)にコピーして、views-view-summary--archive--block.tpl.phpという名前に変更して対応しました。ここまで準備が整ったら、テーマのtemplate.phpに以下のコードを書き込みます。

template.php

/**
 * Change block view url's into WP-look-a-like url's
 * Original code: 
Creating a WordPress like Archive with Drupal | Tessa Bakker
 * @param object $vars
 * @return void
 */
function THEMENAME_preprocess_views_view_summary__archive__block(&$vars) {
  foreach($vars['rows'] as $row) {
    if(is_numeric(substr($row->url, -6, 6))) {
      $row->url = substr($row->url, 0, strlen($row->url) - 2).'/'.substr($row->url, -2, 2);
    }
  }
}

キャッシュをクリアして、アーカイブがどう変わったかを確認してください。狙いどおりに変更が反映されていますか?

月別アーカイブを表示するその他のモジュール

本投稿でご紹介したような設定が面倒という方には、他の選択肢もあります。興味のある方はお調べになってください。

Monthly Archive by Node Type
このモジュールはTokenモジュールを使用して、管理画面で[yyyy]年[m]月と設定するだけでアーカイブのリンクを日本語化できるようです。詳しく調べていませんが、一見したところ設定は簡単なものの、年別のアーカイブなどはできず、デフォルトではブレッドクラムも表示しないようです。

Archive
こちらもよく調べてはいませんが、年別アーカイブが表示できるようです。

コメント (2)

投稿者: よしまさ 投稿日時:

本文の意図を全部汲むわけではないのですが、viewsモジュールの月別表記を修正するだけであれば、modules/nodeにあるviews_handler_argument_dates_various.inc内の以下の部分を修正すればいけると思います。

56行目(バージョンによって異なるかも。Argument handler for a year plus month (CCYYMM)の部分)
$this->format = 'F Y';

$this->format = 'Y年n月';

これで恐らく月別表示が日本語表記になるのではないかな、と思います。
私が開いたときこのファイルはshift-jisになっていましたので、保存するときにutf-8にすると正常に表記されました

投稿者: cocoaspace 投稿日時:

@よしまさ さん

情報共有ありがとうございます。おっしゃるとおり、年月表示に限ってということであれば、views_handler_argument_dates_various.inc内の $this->format = 'F Y'; という部分を Y年n月 に変更し、ファイルをUTF-8で保存することで日本語になりますよね。本投稿でご紹介した方法では、そのシンプルな変更を達成したいがためにいろいろと回りくどいことを好き好んでやっています(笑)。記事の作成時には「年月表示を変更するには $this->format = 'F Y'; の部分を変更したいのですが、そのためにはこのように変更するといいようです。」とか、いろいろ書いていたのですが、記事が長くなってきたのでそういう部分は省いて投稿してしまいました。分かり難くて申し訳ありません。

確かに「月別アーカイブを日本語化するのになぜこんなに手数をかけなければならないのか?」と感じる方も多いと思います。ですので念のために、なぜCocoaSpaceではいろいろと回りくどいことをしたのか、その理由を書かせていただきます。

1. コアや寄贈モジュールを変更しない
ご存知かと思いますが、Drupalのコミュニティでは"コアを変更しないように(参照: Do not hack the core | drupal.org - http://drupal.org/node/144376)"ということが頻繁に聞かれます。Drupalコアの動作を変更するためにコアのプログラムに直接変更を加えるのではなく、カスタムモジュールやカスタムテーマなどから、豊富に用意されたhookを利用して変更を加えることが奨励されています。私はこのhookを利用したサイト構築の柔軟性こそがDrupalの最大の売りだと思っています。コアに変更を加えてしまうと、アップデートのたびにコアに加えた変更を繰り返さなければならなくなり、メンテナンスが難しくなります。変更箇所が多ければ多いほどメンテナンスが難しくなり、最悪の場合メンテナンス不可能なサイトが出来上がるかもしれません。また、コアのプログラムは多くのコミュニティメンバーによってテストされ、セキュリティ面で考慮されていますので、そこに直接変更を加えるのはよくないと言われています。

上記のようなルールはViewsのようなdrupal.orgで管理されている寄贈モジュールについても当てはめて考えられることが多いようです。drupal.orgで管理されている寄贈モジュールは、drupal.orgのセキュリティチームによってテストされているようです(サードパーティのモジュールまでdrupal.orgでセキュリティのテストがされているなんて、Drupalって本当にスゴイですよね!)し、モジュールアップデート時のメンテナンスの容易さという面でも上記のルールを当てはめて考えることは妥当かと思います。寄贈モジュールのなかにはそのモジュール専用のAPIを提供しているものも多くあります。Viewsもその一つです。コアのAPIに加えて、それらのAPIを利用することで、寄贈モジュールのファイルに直接変更を加えなくても、希望通りの動作を実現できることは多いと思います。本投稿に掲載した私の下手なコードでセキュリティはどうなのかということはありますが(笑)、今後Viewsの日付アーギュメントの部分に大きな変更がなければ、アップデートのたびに修正を繰り返す必要はありません。

このような理由から、Viewsのファイルに直接変更を加えるのではなく、別のカスタムモジュールやカスタムテーマから変更を加えるのが正攻法かなと思っています。CocoaSpaceで現在までにご紹介している他のコード、スニペットも、コアや寄贈モジュールに直接変更を加える方法はありません。少々回りくどいと感じる方もいらっしゃるかと思いますが、長い目で見ると逆に"簡単な方法"だと考えています。

2. 多言語サイトでも使用できるようにしたい
CocoaSpaceではファイルに直接日本語を書き込み、UTF-8で保存という方法はなるべくなら採用しないようにしています。その代わりにDrupalのt()ファンクションを使用して日本語の翻訳を用意するようにしています。今回のViewsの変更ではt()ファンクションを使用してコードを書くということではありませんが、Drupalコアの日付には日本語翻訳がありますし、なるべくDrupalで用意された翻訳機能を利用し、それで足りない部分はViewsのAPIを使用しました。本投稿の変更を加えた後、Drupalの言語を英語に変更すると、"January 2010"というように英語の年月表示になると思います。

--- 2010年3月21日追記: サイトの言語を英語にしてちょっと確認してみました。ブロックは"January 2010"という表示になるものの、月別表示のタイトルが"2010年January"という表示になります。このままでは多言語サイトに使えませんね。 ---

おわりに:
上記のような理由があっても、やはり本投稿でご紹介した方法は手数が多いやり方ですよね(笑)。ViewsはDrupalコアよりもファイルサイズが大きいほどたくさんのコードから成り、構成もかなり複雑です。変更を加えるには手数がかかることが多いのは、そのことも理由の一つかもしれません。より簡単な方法を見つけましたら記事に加筆します。今回のような、みなさんからの情報も引き続きお待ちしています。

コメントを追加

Powered by Drupal + Linux