We-Retail example implementation

This is for:

Developer

This article shows an example of how Coveo-powered search could be implemented in Adobe Experience Manager. This sample implementation is built on top of the We.Retail demo site and has two features:

This article also provides details on how these features were implemented in the We.Retail site.

The feature-rich search page

The animation below shows an elaborate Coveo Atomic search page comprising, among others, the following components:

More elaborate Coveo Atomic search page We-Retail

The basic search interface triggered by the search button

The animation below shows how the We-Retail site search button was used to display a modal containing a very basic Coveo Atomic search interface.

Basic search interface displayed when clicking the We-Retail search button
Tip

A better implementation would be to add a standalone search box directly in the page header and to use the redirectionUrl parameter to redirect queries to the feature-rich search page.

Implementation details and code

This section provides general information on how the two search interfaces shown above were implemented. Details such as search interface styling are purposely omitted to focus on core implementation.

Note

The search interface code snippets in this section use Atomic v1 components.

See Upgrade from v1 to v2 and Upgrade from v2 to v3 for instructions on making the code snippets compatible with Atomic v3.

For the full-fledged Coveo atomic search page, a apps/weretail/components/content/searchresults component was created and included in the new page content. The component searchresults.html code is the following:

<sly>
    <atomic-search-interface class="search-results-page">
        <atomic-search-layout>
            <atomic-layout-section section="search">
                <atomic-search-box></atomic-search-box>
            </atomic-layout-section>
            <atomic-layout-section section="facets">
                <atomic-facet-manager>
                    <atomic-facet
                            field="source"
                            label="Source">
                    </atomic-facet>
                    <atomic-facet
                            field="language"
                            label="Language">
                    </atomic-facet>
                    <atomic-timeframe-facet
                            is-collapsed="true"
                            label="Timeframe"
                            with-date-picker="true">
                        <atomic-timeframe unit="hour"></atomic-timeframe>
                        <atomic-timeframe unit="day"></atomic-timeframe>
                        <atomic-timeframe unit="week"></atomic-timeframe>
                        <atomic-timeframe unit="month"></atomic-timeframe>
                        <atomic-timeframe unit="quarter"></atomic-timeframe>
                        <atomic-timeframe unit="year"></atomic-timeframe>
                    </atomic-timeframe-facet>
                </atomic-facet-manager>
            </atomic-layout-section>
            <atomic-layout-section section="main">
                <atomic-layout-section section="status">
                    <atomic-breadbox></atomic-breadbox>
                    <atomic-query-summary></atomic-query-summary>
                    <atomic-refine-toggle></atomic-refine-toggle>
                    <atomic-sort-dropdown>
                        <atomic-sort-expression
                            expression="relevancy descending"
                            label="Relevance">
                        </atomic-sort-expression>
                        <atomic-sort-expression
                            expression="date descending"
                            label="Date">
                        </atomic-sort-expression>
                    </atomic-sort-dropdown>
                    <atomic-did-you-mean></atomic-did-you-mean>
                </atomic-layout-section>
                <atomic-layout-section section="results">
                    <atomic-result-list
                        density="compact"
                        display="grid"
                        image-size="icon">
                        <atomic-result-template>
                            <template>
                                <atomic-result-section-visual>
                                    <atomic-result-icon></atomic-result-icon>
                                </atomic-result-section-visual>
                                <atomic-result-section-badges>
                                    <atomic-result-badge
                                        field="language"
                                        icon="https://raw.githubusercontent.com/Rush/Font-Awesome-SVG-PNG/master/black/svg/language.svg">
                                    </atomic-result-badge>
                                </atomic-result-section-badges>
                                <atomic-result-section-title-metadata>
                                    <atomic-result-printable-uri></atomic-result-printable-uri>
                                </atomic-result-section-title-metadata>
                                <atomic-result-section-bottom-metadata>
                                    <atomic-result-fields-list>
                                        <atomic-field-condition if-defined="date">
                                            <span class="field-label">Date Published:</span>
                                            <atomic-result-date></atomic-result-date>
                                        </atomic-field-condition>
                                    </atomic-result-fields-list>
                                </atomic-result-section-bottom-metadata>
                                <atomic-result-section-title>
                                    <atomic-result-link target="_blank"></atomic-result-link>
                                </atomic-result-section-title>
                                <atomic-result-section-excerpt>
                                    <atomic-result-text field="excerpt"></atomic-result-text>
                                </atomic-result-section-excerpt>
                            </template>
                        </atomic-result-template>
                    </atomic-result-list>
                    <atomic-query-error></atomic-query-error>
                    <atomic-no-results></atomic-no-results>
                </atomic-layout-section>
                <atomic-layout-section section="pagination">
                    <atomic-load-more-results></atomic-load-more-results>
                </atomic-layout-section>
            </atomic-layout-section>
        </atomic-search-layout>
    </atomic-search-interface>
</sly>

Regarding the We.Retail header search button, the /apps/weretail/components/structure/header/modals.html page code was changed to remove the <div class="col-md-12"> section which references the core/wcm search component. It was replaced with the <div class="col-md-12 global-search-container"> below which contains the Coveo Atomic search interface code.

<div class="col-md-12 global-search-container">
    <atomic-search-interface class="search-global">
        <atomic-search-layout>
            <atomic-layout-section section="search">
                <atomic-search-box>
                    <atomic-search-box-query-suggestions></atomic-search-box-query-suggestions>
                </atomic-search-box>
            </atomic-layout-section>
            <atomic-layout-section section="main">
                <atomic-layout-section section="status">
                    <atomic-breadbox></atomic-breadbox>
                    <atomic-query-summary></atomic-query-summary>
                    <atomic-refine-toggle></atomic-refine-toggle>
                    <atomic-sort-dropdown>
                        <atomic-sort-expression
                                expression="relevancy descending"
                                label="Relevance">
                        </atomic-sort-expression>
                        <atomic-sort-expression
                                expression="date descending"
                                label="Date">
                        </atomic-sort-expression>
                    </atomic-sort-dropdown>
                    <atomic-did-you-mean></atomic-did-you-mean>
                </atomic-layout-section>
                <atomic-layout-section section="results">
                    <atomic-result-list
                            density="compact"
                            display="list"
                            image-size="icon">
                        <atomic-result-template>
                            <template>
                                <atomic-result-section-title-metadata>
                                    <atomic-result-printable-uri></atomic-result-printable-uri>
                                </atomic-result-section-title-metadata>
                                <atomic-result-section-title>
                                    <atomic-result-link target="_blank"></atomic-result-link>
                                </atomic-result-section-title>
                                <atomic-result-section-excerpt>
                                    <atomic-result-text field="excerpt"></atomic-result-text>
                                </atomic-result-section-excerpt>
                            </template>
                        </atomic-result-template>
                    </atomic-result-list>
                    <atomic-query-error></atomic-query-error>
                    <atomic-no-results></atomic-no-results>
                </atomic-layout-section>
            </atomic-layout-section>
        </atomic-search-layout>
    </atomic-search-interface>
</div>

A coveo.js file added under apps/weretail/components/structure/header/clientlib/js initializes both search interfaces. This JavaScript file is referenced in apps/weretail/components/structure/header/clientlib/js.txt, instead of utilities.js.

The coveo.js file code looks like the following:

(async () => {
    const initComponent = async (el) => {
        await el.initialize({
            // Retrieve accessToken and organizationId values from the back-end.
            accessToken: article.dataset.accessToken, 1
            organizationId: article.dataset.organizationId, 1
        });
    };

    const initSearchResultPage = async () => {
        const el = document.querySelector(".search-results-page");

        // If the page does not have a search component.
        if (!el) {
            console.log('Coveo not initialized as no result page was found.');
            return;
        }

        // Initialization
        await initComponent(el);

        // Trigger a first search
        el.executeFirstSearch();
    }

    const initGlobalSearch = async () => {
        const el = document.querySelector(".search-global");

        // If the page does not have a search component.
        if (!el) {
            console.log('Coveo not initialized as no global search was found.');
            return;
        }

        // Initialization
        await initComponent(el);

        // Trigger a first search
        el.executeFirstSearch();
    }

    const coveoInit = async () => {
        console.log('Coveo initializing.');

        await import('https://static.cloud.coveo.com/atomic/v1/atomic.esm.js')
            .catch(() => console.log('Error loading coveo scripts.'));

        await customElements.whenDefined("atomic-search-interface");
        await initSearchResultPage();
        await initGlobalSearch();

        console.log('Coveo initialized.');
    };
    await coveoInit();
})();

Search token authentication is only one of several methods you can use to authenticate calls to the Coveo REST API.