web-dev-qa-db-ja.com

パネルページと分類用語の引数

私は新しいDrupal 7サイトで、ページを構築するために Panels を多用している)に取り組んでいます。

view がコンテンツペインに追加されるページがあります。さまざまな理由により、ビューを独自のページにすることはできません。この特定のビューにはコンテキストフィルターがあり、コンテンツ:分類用語IDがあります。ビューは数値引数でうまく機能します。

パネルページで、用語IDの代わりに用語名をビューの引数として使用します。また、さまざまな理由により、パネルに付属するtaxonomy/term/%taxonomy_termオーバーライドを使用できません。

用語名を使用するようにページのコンテキストオプション(設定/引数)を設定すると、引数を機能させることができます。私の問題は、私が使用する必要のある語彙には、大文字とスペースが多い用語が含まれていることです。そのため、URLは判読できなくなります。

パスオートスタイルの用語名を処理できるカスタムの ctools 引数プラグインがあり、用語は小文字でスペースはダッシュに変換されますが、Drupal 6.時間をかけてDrupal 7の時間を費やす前に、より良いソリューションや既存のソリューションがあるかどうかを確認したいと思いました。

要約すれば、

  1. パスfoo/!termのパネルページがあります
  2. パネルページには、分類用語ID引数を持つビューがあり、ビュー引数はURLに基​​づいている必要があります。
  3. foo/Apple-beet-carrotではなくfoo/Apple%20Beet%20CarrotのようなURLが欲しい
  4. taxonomy/term/%taxonomy_termのシステムオーバーライドを使用できません

Drupal 7、Views 3、ctools、およびPanelsを使用して、これを行う最善の方法は何ですか?新しいctools引数プラグインを作成する前に?

3
mpdonadio

もっと良いルートがあるかもしれませんが、私が今考えているものを提案します。

独自のカスタムブロックを作成できます。これは、すでに作成したViewsブロック表示をラップします。どうして?それはあなたが議論を完全にコントロールできるからです。

Viewsブロック表示を独自のカスタムブロックでラップする:

  1. hook_block_info() および hook_block_view() を実装します。
  2. Hook_block_view()内で、プログラムによってビュー表示を呼び出します。ビューの表示はブロックである必要があります(構成済みのようです)。
  3. ビューの表示をインスタンス化するときに、 arg() 関数を使用してURLから引数を取得できます。これはあなた自身のコードなので、それらの引数を使ってあなたがやりたいことは何でもできます。たとえば、nidベースの引数を使用して用語をロードし、用語の適切な名前を取得し、必要に応じてURLデコードしてから、ディスプレイにフィードできます。
  4. ビュー表示を実行して結果を取得し、ブロックの出力として返します。

次に、ビューによって提供されたブロックをパネルに埋め込む代わりに、カスタムモジュールで作成したブロックを埋め込みます。繰り返しますが、Viewをプログラムで呼び出したため、渡された引数を完全に制御できました。

複雑に聞こえますが、思ったより簡単です。以下は、ビューを呼び出す方法のわかりやすい例です(必要に応じて変更できます)。

$view = views_get_view('my_foobar_view');
$result = $view->execute_display('block_display_baz');
$term_id = arg(2); // Get the term from my-panel/foo/<term id>
$view->set_arguments(array($term_id));
$view->execute();
if(!empty($view->result)) {
  foreach($view->result as $result) {
    // Do something with $result...
  }
}

このG.D.O.ドキュメント は、プログラムでビューを埋め込む方法について、より多くの例を提供できます。

2
amateur barista

これらのパネルのhook_menu()キーは任意(ユーザーが定義)なので、100%正確な例を投稿することはできませんが、既存のhook_menu()項目を「ハッキング」またはインターセプトする方法の一般的な解決策を1つ示します。

  1. Menu_routerテーブルに移動します。
  2. パネルに定義したURLパスを検索します。完全一致検索を使用して開始できます。何も表示されない場合は、「... path = "foo/bar/baz"ではなくselect * from menu_router where path like "%bar%"」のようなワイルドカード(%)検索を実行します。これにより、そのメニュー項目についてのすべて、それを定義したモジュール、それが呼び出す関数、それが引数であるもの、および引数のロード関数(存在する場合)がすべてわかります。
  3. この情報を準備したら、メニュー項目を定義したモジュールに移動できます。そのモジュールのhook_menu実装に移動し、そのキーを探します。メニュー項目を構成するさまざまなキーをメモします。変更する必要があるのがタイトルコールバックだけである場合に、独自のメニュー項目を定義するのは過剰な場合があります。このため、次に hook_menu_alter() を使用します。
  4. カスタムモジュールにhook_menu_alterを実装します。

アイテム#4の例。

/**
 * Implementation of hook_menu_alter.
 *
 * Intercept 'foo/bar/baz' and 'taxonomy/term/%taxonomy_term'.
 */
function mymodule_menu_alter(&$items) {
    // The string to the right is the name of the function that is going to get called
    // to determine that page's title. We just substituted what defined there by
    // someone else with our own function.
    $items['foo/bar/baz']['title callback'] = 'mymodule_panel_title_callback';

    // Here I modify a separate menu item.
    // Redirect current page workflow to my module.
    // Note that the function taxonomy_term_load() will be called with whatever argument is in the
    // third element of the path, so "taxonomy/term/123" will call taxonomy_term_load(123) and the
    // result will be passed to mymodule_taxonomy_term_page().
    $items['taxonomy/term/%taxonomy_term']['page callback'] = 'mymodule_taxonomy_term_page';
    // I'm doing this to state the "obvious" - that taxonomy_term_load() will be passed 123 in "taxonomy/term/123".
    // Also to say that there's not much you can do to to modify this particular menu item attribute.
    // Since %taxonomy_term is part of the menu item key, if you modify that to be something else, such as
    // %mymodule_taxonomy_term, you would be basically defining a new menu item (If I'm not mistaken).
    // If you find yourself in the position that you need to modify the "auto-loader wildcard component", then
    // that might be your cue to define your own menu item, and then call back 'taxonomy/term/%taxonomy_term'
    // from your own callback.
    $items['taxonomy/term/%taxonomy_term']['page arguments'] = array(2);

}

次に、物事をより複雑にするために、問題の一部として、'taxonomy/term/%taxonomy_term'の「オートローダーワイルドカードコンポーネント」を変更する必要があり、このメニュー項目がDrupalコア分類:上記のコメントで述べたように、hook_menu_alter()でそれをいじると、メニュー定義が台無しになる可能性があります。

したがって、2つのオプションが残されています。独自のメニュー項目を定義し、1)独自のメニュー項目からCoreによって定義されたメニュー項目をコールバックするか、2)元のメニュー項目によって呼び出された関数の本体にあるコードをカスタム関数にコピーします。 #2を実行してエラーが発生した場合は、module_load_include()を使用して、コア関数が置かれているファイルをインクルードしてください。 コアを例として使用したことに注意してください。ただし、この手法はcontribモジュールにも適用できます。

/**
 * Implementation of hook_menu().
 */
function mymodule_menu() {
  $items = array();
  // Defining an arbitrary path, change it to what makes logic for you.
  // Using a simple wildcard.
  $items['mymodule/term/%']  = array(
    'page callback' => 'mymodule_taxonomy_term_page',
    // Define other arguments, skipping for the sake of brevity.
  );
  // This menu item will call function mymodule_taxonomy_term_load(), and pass
  // the results of that call to mymodule_taxonomy_term_page.
  // Note that the path I define here conflicts with the path above, and that you should use either or, but not both.
  // Else menu router will get confused and will not know which one to call. The same applies to paths created by
  // core or contrib, it is important not to define them twice.
  $items['mymodule/term/%mymodule_taxonomy_term']  = array(
    'page callback' => 'mymodule_taxonomy_term_page',
    // Stating that mymodule_taxonomy_term_load() will be passed the 3rd argument in the path (count is zero-based).
    'page arguments' => array(2),
    // Define other arguments, skipping for the sake of brevity.
  );

  return $items;
}

// Meantime, in another part of your module...
/**
 * Returns a taxonomy term object based.
 */
function mymodule_taxonomy_term_load($term) {
  // Here you could do all the custom logic you want. Depending on what you put here, you might be
  // able to even support numeric term ids and non-numeric term names in the same path. Example:

  if(is_numeric($term)) {
    $term_object = mymodule_taxonomy_term_load($term);
  } else {
    // String detected.
    // Do some cleanup first, and then try to load a taxonomy term with the cleaned string.
    $clean_term_string = somecleanup_function($term);
    $term_object = taxonomy_get_term_by_name($clean_term_string);
  }

  if($term_object) {
    // Profit!
    return $term_object;
  } else {
    // Return something we can reliably validate against in our callback...
    return FALSE;
  }
}

// And then in your hook_menu() callback...

/**
 * Render a page based on term? 
 *
 * @param var $term - A term object if mymodule_taxonomy_term_load() was successfull, else FALSE.
 */
function mymodule_taxonomy_term_page($term) {
  if($term === FALSE) {
    // Degrade gracefully, e.g., show a custom error page...
  } else {
    // If our example `'taxonomy/term/%taxonomy_term'` is defined by Core, and we did not implement hook_menu_alter() for it,
    // call whatever function that callback defines. Note that we accomplished our mission here by loading $term the
    // way we wanted to in the auto-loader function, so we don't really need much processing here, but we could do more if needed.
    return somefunction_defined_bycore($term);

    // Else the other option was to copy and paste somefunction_defined_bycore()'s function body into here and return it.
    // Do some processing...
    return $something;
  }
}
1
amateur barista

私が受け入れたブロックベースのソリューションの代替は、カスタムctoolsコンテンツタイプを作成することです。これはモジュールのヘルプの外にまばらに記載されていますが、c-toolsに同梱されている example module があります(通常はctools/ctools_plugin_exampleディレクトリ)と別のサンプルがあります here を見つけることができます。

基本的に、これはビュー(および他のモジュール)がパネルペインのコンテンツとして使用できるようにするために使用する方法と同じです。

ブロックに対する利点は、引数を渡すためにctoolsコンテキストを使用するように設定できることです(これはブロックの弱点です)。これらを使用して、多くのプロジェクトで成功しています。 argmenu_get_object 、またはその他のメソッドに直接アクセスする代わりに、ctoolsコンテキストを使用して、後でコンテンツをサイトへの統合方法から分離するための素晴らしい抽象化を提供します。

ただし、この特定のケースでは、パネルコンテキストを使用することも欠点です。適切な方法は、ctoolsコンテンツプラグインを作成して、「かわいい」用語をURLからコンテンツタイプが使用する用語IDに変換することです。パネルコンテンツを構成してURL引数を渡すことができますが、パネルコンテンツタイプは解析/変換を行う必要があるため、これは適切な方法ではありません(違反する可能性があります [〜#〜] solid [ 〜#〜] )。コンテキストプラグインを作成すると、パネルコンテンツとしてビューを使用して直接使用できるようになります。

0
mpdonadio