Live Search CIF Component

最終更新日: 2023-12-05

Adobe Commerceのライブ検索は、迅速で関連性が高く、直感的な検索操作を、追加費用なしで実現します。 Adobe Senseiを活用したライブ検索では、人工知能と機械学習アルゴリズムを使用して、集計された訪問者データを深く分析します。 このデータをAdobe Commerceカタログと組み合わせると、関連性の高いパーソナライズされたショッピングエクスペリエンスが得られます。

ここでは、AEM CIFコンポーネントを使用して Live Search 製品リストページ (PLP) ウィジェットをAEMサイトに貼り付けます。

前提条件

このトピックでは、 AEM環境 を設定します。

PLP コンポーネントには、 Live Search ポップオーバーCIFコンポーネント をインストールします。 PLP ウィジェットには、ポップオーバーによって生成されるブラウザセッション変数が必要です。

コンポーザーを更新

イベンティングモジュールの追加先 ui.frontend/package.json.

27 行目で、次の内容を変更します。

...
  },

  "devDependencies": {

    "@babel/core": "^7.3.4",
...

リダイレクト先は次のとおりです。

...
  },
  "type": "module",
  "devDependencies": {
    "@adobe/magento-storefront-event-collector": "^1.5.4",
    "@adobe/magento-storefront-events-sdk": "^1.5.4",
    "@babel/core": "^7.3.4",
...

ファイルの変更

有効にするには複数のファイルを更新する必要があります Live Search 機能。 次のファイルを編集します。 行番号は、次に示すように少し異なる場合があります。

  • ui.apps/src/main/content/jcr_root/apps/venia/clientlibs/clientlib-cif/.content.xml

    追加 core.cif.productlist.v1 から embed 行。

    embed="[core.cif.components.common,core.cif.components.product.v3,core.cif.components.productcarousel.v1,core.cif.components.productcollection.v2,core.cif.components.productteaser.v1,core.cif.components.searchbar.v2,core.cif.components.header.v1,core.cif.components.carousel.v1,core.cif.components.categorycarousel.v1,core.cif.components.featuredcategorylist.v1,core.cif.components.storefront-events.v1,core.cif.components.extensions.product-recs.storefront-events-collector.v1,core.wcm.components.commons.site.link,core.cif.productlist.v1]"
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/clientlibs/.content.xml

    ファイルの作成 .content.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
      jcr:primaryType="cq:ClientLibraryFolder"
      allowProxy="{Boolean}true"
      categories="[core.cif.productlist.v1]"
      jsProcessor="[default:none,min:none]"/>
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/clientlibs/css.txt

    ファイルを作成します。 css.txt:

    #base=css
    
    productlist.css
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/clientlibs/css/productlist.css

    ファイルを作成します。 productlist.css

      /* #search-plp-root */
    
    html {
      font-size: 62.5% !important;
    }
    
    body {
      font-size: 1.6rem;
    }
    
    .root.container {
      max-width: inherit;
    }
    
    .container {
      margin-left: auto;
      margin-right: auto;
    }
    
    div.ds-sdk-sort-dropdown {
      z-index: 9;
    }
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/clientlibs/js.txt

    ファイルを作成します。 js.txt:

    js/productlist.js
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/clientlibs/js/productlist.js

    ファイルを作成します。 productlist.js:

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~ Copyright 2023 Adobe
    ~
    ~ Licensed under the Apache License, Version 2.0 (the "License");
    ~ you may not use this file except in compliance with the License.
    ~ You may obtain a copy of the License at
    ~
    ~     http://www.apache.org/licenses/LICENSE-2.0
    ~
    ~ Unless required by applicable law or agreed to in writing, software
    ~ distributed under the License is distributed on an "AS IS" BASIS,
    ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    ~ See the License for the specific language governing permissions and
    ~ limitations under the License.
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    "use strict";
    
    class ProductList {
      constructor() {
        const stateObject = {
          categoryName: null,
          currentCategoryUrlPath: null,
        };
        this._state = stateObject;
        this._init();
      }
    
      _init() {
        this._initWidgetPLP();
      }
    
      _injectStoreScript(src) {
        const script = document.createElement("script");
        script.type = "text/javascript";
        script.src = src;
    
        document.head.appendChild(script);
      }
    
      async _getStoreData() {
        // get from session storage
        const sessionData = sessionStorage.getItem(
          "WIDGET_STOREFRONT_INSTANCE_CONTEXT"
        );
        // WIDGET_STOREFRONT_INSTANCE_CONTEXT is set from searchbar/clientlibs/js/searchbar.js
        // if not, we will need to retrieve from graphql separately here.
    
        if (sessionData) {
          this._state.dataServicesSessionContext = JSON.parse(sessionData);
          return;
        }
      }
    
      getStoreConfigMetadata() {
        const storeConfig = JSON.parse(
          document
            .querySelector("meta[name='store-config']")
            .getAttribute("content")
        );
    
        const { storeRootUrl } = storeConfig;
        const redirectUrl = storeRootUrl.split(".html")[0];
        return { storeConfig, redirectUrl };
      }
    
      async _initWidgetPLP() {
        if (!window.LiveSearchPLP) {
          const liveSearchPlpSrc =
            "https://plp-widgets-ui.magento-ds.com/v1/search.js";
          this._injectStoreScript(liveSearchPlpSrc);
          // wait until script is loaded
          await new Promise((resolve) => {
            const interval = setInterval(() => {
              if (window.LiveSearchPLP && window.LiveSearchAutocomplete) {
                // Widget expects LiveSearchAutocomplete already loaded to rely on data-service-graphql
                clearInterval(interval);
                resolve();
              }
            }, 200);
          });
        }
        await this._getStoreData();
        const { dataServicesSessionContext } = this._state;
        if (!dataServicesSessionContext) {
          console.log("no dataServicesSessionContext");
          return;
        }
    
        const root = document.getElementById("search-plp-root");
        if (!root) {
          console.log("plp root not found.");
          return;
        }
        // get dataset from root
        const categoryUrlPath = root.getAttribute("data-plp-urlPath") || "";
        const categoryName = root.getAttribute("data-plp-title") || "";
        const storeDetails = {
          environmentId: dataServicesSessionContext.environment_id,
          environmentType: dataServicesSessionContext.environment,
          apiKey: dataServicesSessionContext.api_key,
          websiteCode: dataServicesSessionContext.website_code,
          storeCode: dataServicesSessionContext.store_code,
          storeViewCode: dataServicesSessionContext.store_view_code,
          config: {
            pageSize: dataServicesSessionContext.page_size,
            perPageConfig: {
              pageSizeOptions: dataServicesSessionContext.page_size_options,
              defaultPageSizeOption:
                dataServicesSessionContext.default_page_size_option,
            },
            minQueryLength: dataServicesSessionContext.min_query_length,
            currencySymbol: dataServicesSessionContext.currency_symbol,
            currencyRate: dataServicesSessionContext.currency_rate,
            displayOutOfStock: dataServicesSessionContext.display_out_of_stock,
            allowAllProducts: dataServicesSessionContext.allow_all_products,
            locale: dataServicesSessionContext.locale,
            currentCategoryUrlPath: categoryUrlPath,
            categoryName,
            displayMode: "", // "" for plp || "PAGE" for category/catalog
          },
          context: {
            customerGroup: dataServicesSessionContext.customer_group,
          },
          route: ({ sku }) => {
            return `${
              this.getStoreConfigMetadata().redirectUrl
            }.cifproductredirect.html/${sku}`;
          },
          searchQuery: "search_query",
        };
        setTimeout(() => {
          console.log("init PLP");
          window.LiveSearchPLP({ storeDetails, root });
        }, 0);
      }
    }
    
    (function () {
      function onDocumentReady() {
        new ProductList({});
      }
    
      if (document.readyState !== "loading") {
        onDocumentReady();
      } else {
        document.addEventListener("DOMContentLoaded", onDocumentReady);
      }
    })();
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productlist/productlist.html

    ファイルを作成 productlist.html:

    <div
    data-sly-use.productList="com.adobe.cq.commerce.core.components.models.productlist.ProductList"
    id="search-plp-root"
    class="productlist__root"
    data-plp-urlPath="${productList.storefrontContext.urlPath}"
    data-plp-title="${productList.title}">
    </div>
    
  • ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/searchresults/.content.xml

    編集 .content.xml 6 行目:

    sling:resourceSuperType="venia/components/commerce/productlist"
    
  • ui.content/src/main/content/jcr_root/content/venia/language-masters/en/search/.content.xml

    編集 .content.xml 21-22 行目:

    sling:resourceType="venia/components/commerce/productlist"
    
  • ui.content/src/main/content/jcr_root/content/venia/us/en/search/.content.xml

    編集 .content.xml 26 行目:

    sling:resourceType="venia/components/commerce/productlist"
    
  • ui.frontend/src/main/components/App/App.js

    編集 App.js 47 行目、 ../../site/main.scss:

    import '@adobe/magento-storefront-event-collector';
    
  • ui.tests/test-module/specs/venia/productlist-dialog.js

    編集 productlist-dialog.js および変更 describe から describe.skip 20 行目:

    describe.skip('Product List Component Dialog', function () {
    

非 PLP ページ

PLP ウィジェットを使用するのではなく、デフォルトのカテゴリまたはカタログページが必要なカテゴリが存在する場合があります。 AEMでは、これらのカテゴリページを手動で設定する必要があります。

  1. 作成者ページで、カテゴリページテンプレートを選択します。 ヴェニアストア — ホーム > カタログページ > Venia ストア — カテゴリページ 「外観をショッピング」を選択するか、新しいページテンプレートを作成します。

テンプレートを選択

  1. 次をクリック: プロパティ 」セクションで、 コマース タブをクリックします。

プロパティを選択

  1. 選択したカテゴリページテンプレートで表示するカテゴリを選択します。

カテゴリを選択

このページ