如何在 Drupal 9 中实现 Algolia Search(第 2 部分)

已发表: 2022-09-13

在本系列的前一章中,我们向您介绍了配置 Algolia 仪表板和您的 Drupal 站点以索引 Algolia 上的站点内容的过程。 在本章中,您将学习如何在您的 Drupal 网站上显示 Algolia 搜索结果。

要显示搜索结果,您需要创建一个 Drupal 自定义块并将该块放在/search页面上。 此外,您还将了解如何使用 Algolia 的InstantSearch库。 请注意,此过程假设您对如何在 Drupal 中创建自定义模块有基本的了解,因此我们不会深入探讨创建自定义模块的过程。 阅读本文以了解如何在 Drupal 9 中以编程方式创建自定义模块。

这是 2 部分系列文章的第二章。 单击此处阅读我们讨论如何配置 Algolia 和 Drupal 的第一部分。

如何在 Drupal 9 中实现 Algolia Search(第 2 部分)

为界面构建自定义块

我们将使用以下结构来创建我们的自定义块。

 algolia_search_interface - js/ - algolia.js - src/ - Plugin - Block - DemoSearchBlock.php - templates/ - algolia_search_interface-block.html.twig - algolia_search_interface.info.yml - algolia_search_interface.libraries.yml - algolia_search_interface.module

声明库

如前所述,我们将使用 Algolia 的 InstantSearch 库来访问搜索结果。 因此,让我们在 algolia_search_interface.libraries.yml 中声明所有库,如下所示:

 algolia-javascript: js: https://cdn.jsdelivr.net/npm/[email protected]/dist/algoliasearch-lite.umd.js : { type: external } https://cdn.jsdelivr.net/npm/[email protected] : { type: external } js/algolia.js: {preprocess: false} dependencies: - core/drupalSettings css: theme: https://cdn.jsdelivr.net/npm/[email protected]/themes/algolia-min.css: { type: external, minified : true }

访问和设置变量

在演示搜索块(DemoSearchBlock.php)中,我们将简单地从 Drupal 配置中访问 Algolia 变量,并使用以下代码将它们分配给 drupalSettings:

 public function build() { // Get Algolia config. $config = $this->configFactory->get('search_api.server.algolia_search'); $app_id = $config->get('backend_config.application_id'); $api_key = $config->get('backend_config.api_key'); $index_name = $this->configFactory->get('search_api.index.vehicles_data')->get('options.algolia_index_name'); return [ '#theme' => 'demo_search_block', '#attached' => [ 'library' => 'algolia_search_interface/algolia-javascript', 'drupalSettings' => [ 'app_id' => $app_id, 'index_name' => $index_name, 'api_key' => $api_key, ], ], '#cache' => [ 'contexts' => [ 'url.path', 'url.query_args', ], ], ]; }

添加模板

现在您需要为自定义块添加模板。 因此,让我们在 algolia_search_interface.module 中为我们的自定义块定义 hook_theme:

 /** * Implements hook_theme(). */ function algolia_search_interface_theme($existing, $type, $theme, $path) { return [ 'demo_search_block' => [], ]; }

定义容器

现在,让我们定义我们的模板数据来呈现搜索结果。 我们将简单地定义 InstantSearch 库将呈现结果的容器。 我们将在 algolia_search_interface-block.html.twig 中添加 4 个容器:

 - Searchbox (#searchbox) - Search results (#hits) - Facets (#filter-widget) - Pagination (#pagination)
 <div class="demo-instant-search"> <div class="algolia-searchbox"></div> <div class="align-left"> <div class="filter-header">{{ 'Manufacturer'|t }}</div> <div></div> </div> <div class="right-col"> <div></div> </div> </div> <div></div>

显示搜索结果

现在,您拥有了显示搜索结果所需的所有要素。 那么让我们看看如何使用 InstantSearch 来显示我们的结果。

首先,让我们从 drupalSettings 变量中获取索引名称、应用程序 ID 和应用程序键。 我们需要将它们传递给 algolia.js 中的 Algolia API。

 const index_name = drupalSettings.index_name; const app_id = drupalSettings.app_id; const api_key = drupalSettings.api_key;

准备好应用程序键和索引名称后,您需要初始化并启动 InstantSearch。

 const search = instantsearch({ indexName: index_name, searchClient: algoliasearch(app_id, api_key), }); search.start();

此时,您不会在搜索页面中看到任何差异,因为您尚未将任何小部件添加到 InstantSearch。 因此,让我们在即时搜索中添加一个搜索框小部件。

 search.addWidget( instantsearch.widgets.searchBox({ container: '#searchbox', }) );

请注意,我们使用了InstantSearchaddwidget()函数来添加单个小部件。 当使用多个小部件时, addwidget()是不可行的。 您将需要以下列方式使用它:

 search.addWidgets([ instantsearch.widgets.searchBox({ container: '#searchbox', }), instantsearch.widgets.hits({ container: '#hits' }), ]);

现在您将能够在搜索页面上看到搜索结果。 但正如我们所见,结果是非常原始的格式:

Algolia 搜索结果 - 原始格式

为了改进这一点,让我们使用模板属性格式化结果,如下所示:

 instantsearch.widgets.hits({ container: '#hits', templates: { item: ` <h3 class="title">{{{title.value}}}</h3> <p class="detail"> {{{field_manufacturer}}} </p> <p class="uri">{{{uri}}} </p> `, }, }),

请注意,虽然结果看起来不错,但有时我们需要对数据进行一些处理,然后才能将其显示在页面上。 例如在上面的代码中,URI 值是`public://`格式。 在这里,我们可以使用transformItems属性来根据我们的要求更改结果。

 instantsearch.widgets.hits({ container: '#hits', transformItems(items) { return items.map(item => ({ ...item, url: item.uri.replace('public://', /sites/default/files/'), })); }, templates: { item: ` <h3 class="title">{{{title.value}}}</h3> <p class="detail"> {{{field_manufacturer }}} </p> <p class="uri">{{{url}}} </p> `, }, })

一旦结果集就位,您现在可以移动以显示构面数据以过滤我们的搜索条件。 您将使用相同的addWidgets()函数来显示构面。

 search.addWidgets([ instantsearch.widgets. refinementList({ container: '#filter-widget, attribute: 'field_manufacturer', }), ]);

属性选项定义了我们想要显示分面的字段名称。 请记住,这也需要在 Algolia 仪表板中进行预配置。

最后,让我们添加分页以显示更多结果。

 search.addWidgets([ instantsearch.widgets. pagination({ container: '#pagination, }), ]);

我们完成了! 这就是最终代码的样子

const index_name = drupalSettings.index_name; const app_id = drupalSettings.app_id; const api_key = drupalSettings.api_key; if(index_name && app_id && api_key) { const search = instantsearch({ indexName: index_name, searchClient: algoliasearch(app_id, api_key), }); search.addWidgets([ instantsearch.widgets.searchBox({ container: '#searchbox', }), instantsearch.widgets.hits({ container: '#hits', transformItems(items) { return items.map(item => ({ ...item, url: item.uri.replace('public://', '/sites/default/files/'), })); }, templates: { item: ` <h3 class="title">{{{_highlightResult.title.value}}}</h3> <p class="detail"> {{{_highlightResult.field_manufacturer.value}}} </p> <p class="uri"><img src="{{{url}}}" /></p>`, }, }), instantsearch.widgets.refinementList({ container: '#filter-widget', attribute: 'field_manufacturer', }), instantsearch.widgets.pagination({ container: '#pagination', }) ]); search.start(); } else { throw "Algolia settings missing";}

最后的想法

当我们结束我们的两部分文章系列时,我们希望您对 Algolia 有足够的了解。 我们已经介绍了如何将 Algolia 搜索与 Drupal 集成以构建强大的消费级搜索。 我们还讨论了使用 InstantSearch 库来自定义搜索结果。 正在寻找一家 100% 专注于 Drupal 的公司,可以帮助您建立雄心勃勃的 Drupal 体验,同时利用网络的精华? 我们很乐意听取您的意见!