Algolia e usando instantsearch.js do seu script para Shopify

"Bons artistas copiam, grandes artistas roubam." - Steve Jobs

Inspirado por pimoroni.com Eu queria implementar uma pesquisa semelhante na nossa loja virtual, buyzero.de Também. buyzero.de é actualmente alimentado por Shopify.

A pesquisa mostra os resultados à medida que você digita - na página principal, substituindo dinamicamente o conteúdo préviamente exibido. Muito legal, muito útil - e muito, muito rápido (graças a Algolia!)

Desde que lutei com a documentação disponível sobre a Algolia, e o seu serviço de bordo não foi muito útil, tive que descobrir as coisas sozinho, e através do Googling extensivo.

Este é um resumo da minha experiência na implementação da Algolia. Fi-lo num único dia, numa única sessão de cerca de 12 - 14 horas de codificação.

Preparação Sugerida: injeção de código de desenvolvimento em sua página

Sugiro a utilização da extensão Google Chrome Tampermonkey para injetar CSS e Javascript do seu disco rígido local enquanto você se desenvolve.

Para fazer isso, você tem que habilitar o acesso a arquivos para o Tampermonkey. Abrir:

chrome://extensions

Clique em Detalhes e mude "Permitir acesso a URLs de arquivos" em

imagem

imagem

Crie o seguinte novo script de usuário em Tampermonkey:

// ==UserScript====
// @nome Algolia-Inject
// @namespace https://pi3g.com/
// @versão 0.5
// @description injectar ficheiro local para testar Algolia!
// @author Maximilian Batz
// @grant GM_getResourceText
// @grant GM_addStyle
// @noframes
// @include https://buyzero.de/*
// @resource YOUR_CSS file://D:\algolia_jr.css
// @require file://D:\algolia_jr.js

// ===/UserScript====

var my_css = GM_getResourceText ("YOUR_CSS");
GM_addStyle(my_css);

Explicação:

  • você tem que conceder o getResourceText e o addStyle para poder acessar e injetar o arquivo CSS
  • noframes por não executar uma segunda vez nos frames que Shopify aparentemente carrega, e que também coincidiriam com o domínio
  • incluir -> irá coincidir no buyzero.de. Você pode querer mudar essa linha Sorria
  • recurso utilizado para importar arquivo CSS. Forneça o caminho ... no Linux ele pode ser file:///home/whatever/whatever - notar a tripla barra oblíqua para a frente
  • exija - inclua seu arquivo javascript
  • userscript: este é o userscript para adicionar o arquivo CSS

Adicionando o Código Algolia

Com a parte de "como se desenvolver" fora do caminho, aqui está o meu código como código de amostra num pequeno e agradável ficheiro ZIP.

Por favor, não copie pasta deste blog, pois não tenho certeza se o WordPress vai destruir a formatação do código ... use o .js no arquivo ZIP para copiar.

Por favor note que as dependências Algolia / arquivos JavaScript já foram instalados em nosso tema Shopify - instalando o plugin Algolia Shopify. Também a nossa datastore foi configurada, etc. O Algolia já estava (e ainda está) a servir resultados de pesquisa numa gota abaixo enquanto você digitava na caixa de pesquisa.

Eu acompanho-o através das partes importantes do código:

começamos aj_setup() uma vez que o documento esteja pronto, para injetar nossa nova funcionalidade de busca.

Por favor, note que eu uso aj para preender as minhas funções & id's para este script. Você pode usar o que quiser, não é exigido por Algolia.

O recipiente

em aj_setup() eu preparei um novo container para os resultados da busca (provavelmente seria melhor incluir isso diretamente no seu arquivo temático - para desenvolver isso foi mais fácil).

esta é a parte HTML da pesquisa

$(".main-content").before('<div id="aj-search-container" class="aj-main-content full-width"><div class="background"><div class="pattern"><div class="container"><div class="row"><div class="col-md-12"><div class="row"><div class="col-md-12 center-column content-without-background">'+
                         "
"+
                           "<h1>Suchresultate für: <span id='sc-query'></span></h1>" +
                           "
" +
                             "
" +
                             "
" +
                             "
" +
                             "
" +
                           "
" +
                           "
" +
                               "
" +
                               "
" +
                               "
" +
                           "</DIV" +
                       "
" +
                       '</div></div></div></div></div></div></div></div>'
                       );
  • Eu dou-lhe a identificação entre recipientes de busca, ser capaz de mostrar / esconder todos os resultados do contentor de pesquisa
  • a maioria dos div's, incluindo contentor são necessários para um estilo compatível com o nosso tema atual - use conforme necessário
  • sc-query é usado para espelhar a pesquisa que o usuário digitou atualmente, para mostrar que o sistema atualiza os resultados dinamicamente em seu nome (há código para fazer isso - ler em)
  • aj-right-container contém filtros para chegar às "facetas" da busca. O usuário pode escolher uma ou várias marcas para mostrar, categorias de produtos, e nós incluímos um filtro de preço
  • aj-clear-all conterá um link para uma facetadura clara - para retornar todos os resultados que correspondam à consulta do usuário
  • aj-left-container contém os resultados da pesquisa. aj-stats conterão estatísticas sobre a pesquisa (resultados da pesquisa + tempo gasto na pesquisa), aj-search-results conterão os resultados e aj-search-pagination conterá a paginação

O modelo de sucesso

mais uma vez, isto provavelmente iria directamente para a sua página em vez de ser injectado via Javascript.

    $(".main-content").before(''+
       '+
'          <div class="aj-hit">'+
'            <div class="aj-hit-image">'+
'              <a href="/pt/{{product_link}}/"><img src="{{image}}" alt="{{título}}"></a>'+
'            </div>'+
'            <div class="aj-hit-content">'+
'              <div class="aj-hit-title"><a href="/pt/{{product_link}}/">{{{{_highlightResultado.title.value}}}{{{variant_title}}}</a></div>'+
               '<p class="aj-hit-description">{{{{_highlightResult.body_html_safe.value}}}} &nbsp; <a href="/pt/{{product_link}}/">" mehr</a></p>'+
               '<p class="aj-hit-sku"><a href="/pt/{{product_link}}/">{{sku}}</a></p>'+
'              <div class="aj-hit-bottominfos">' +
'                <div class="aj-hit-price">{{preço}} €</div>' +
'                <div class="aj-hit-stock">auf Lager </div>'+
'                <div  class="aj-hit-link"><a href="/pt/{{product_link}}/">zur Produktseite</a></div>'+
'             </div>'+
             '</div>'+
             ">" +
           '</div>'+
         '+
     '');

Este modelo é inserido como "script". Esta é a forma recomendada pelos documentos da Algolia.

É usado para renderizar um resultado de pesquisa, ou hit.

Aqui, dentro aj-hit Já o fizemos:

  • aj-hit-imagee {{{imagem}}} como espaços reservados para inserir os valores correctos mais tarde
  • aj-hit-titleusando {{{{_highlightResult.title.value}}}} - Também ligo no {{{{variant_title}}} para fornecer um título completo para variações
  • aj-hit-descriptionpara tornar a descrição do produto - {{{{_highlightResult.body_html_safe.value}}}}
  • aj-hit-price para o {{{preço}} - não se esqueça de adicionar a sua moeda (ou adicioná-la modificando a variável passada para o modelo)
  • aj-hit-stockpara mostrar o quanto {{{inventory_quantity}} temos
  • aj-hit-link - finalmente, um link para a página do produto. {{link_do_produto}}

Tudo isto é bem (IMHO) com o meu ficheiro CSS. Styling está fora do escopo deste post do blog, consulte buyzero.de para alguma inspiração e depois codifique a sua.

Mais sobre {{{_highlightResultado.title.value}}}

Variáveis exibidas usando três colchetes não serão escapadas por Algolia para HTML. Isto é usado aqui, para permitir o destaque.

Algolia irá automaticamente colocar Tags para você ao redor das partes do título, etc. que foram combinadas no _aluzResultado variável. O usuário pode usar a na saída, para mostrar ao usuário porque o resultado da pesquisa é considerado relevante para sua pesquisa.

Mais tarde mostrar-lhe-ei como modificar os valores que são passados para o template, pois não vai querer renderizar todo o corpo de descrição do seu produto, por exemplo.

aj_setup_search

var pb = aj_setup_search();

Para lidar com a busca mais tarde, retornamos uma variável da função de configuração (chamada var point_both dentro da função setup_search. pb é a abreviatura).

	
var search = instantsearch({
	  appId: 'YOUR_APP_ID',
	  apiKey: 'YOUR_API_KEY', // search only API key, no ADMIN key
	  indexName: 'shopify_buyzero_de_products',
	  urlSync: true,
	  searchParameters: {
		hitsPerPage: 10
	  },
	  searchFunction(my_helper){
		  point_both.ihelper = my_helper;
		  //search.helper.setQuery('Pi 3'); //sic!
		  //my_helper.search(); //sic!
		  
		  if(my_helper.state.query === '') {	
				return;
			}
		  my_helper.search();
	  } //end searchFunction
	});//end instantsearch setup

Aqui nós configuramos a pesquisa (como mencionado anteriormente, a pesquisa instantânea já está incluída e disponível na página através de outro arquivo .js).

Tens de passar:

  • seu appId
  • apiKey
  • indexName

vais receber isto do teu backend Algolia. Lá você também pode navegar por suas estruturas de dados, e ver quais parâmetros você pode usar para facetar, por exemplo.

A parte realmente importante é a função searchFunction (my_helper).

O helper permite-lhe conduzir a pesquisa através do seu próprio script, em vez de o activar a partir de um widget de caixa de pesquisa que é configurado com o Algolia's instantsearch.

É importante criar uma referência a este ajudante, nesta função em particular.

point_both.ihelper = my_helper;

Aceder mais tarde ao helper a partir da variável de pesquisa irá não trabalho.

Na verdade, você precisa de ambos. Vês este código de exemplo, eu comentei?

//search.helper.setQuery('Pi 3'); //sic!

//my_helper.search(); //sic!

sic é a palavra latina para "assim". Ou seja, tem de ser acessada de duas maneiras diferentes para definir a consulta e depois executar a pesquisa.

Além disso, você precisa para adicionar o meu_helper.search() aqui. Isto vai - como eu me lembro - permitir que seus widgets atualizem a pesquisa corretamente... se você achar que seus resultados não estão atualizados, verifique se você os tem aí!

Depois de adicionarmos os widgets - que discutiremos a seguir - terminamos a configuração da pesquisa com o seguinte código:

search.start();
point_both.search = procurar;
ponto de retorno_ambos;

Aqui também adicionamos uma referência ao próprio objeto de busca, e o retornamos para a função aj_setup.

Note que o point_both tem agora acesso ao objecto "search", e ao objecto de ajuda especial "ihelper" que obtivemos dentro da função searchFunction.

Adicionando o primeiro widget

vamos adicionar o resultado como o primeiro widget:

search.addWidget(
   instantsearch.widgets.hits({
     contentor: '#aj - resultados de pesquisa',
     modelos: {
       item: document.getElementById('aj-hit-template').innerHTML,
       vazio: "Es konnten leider keine Resultate für die Suchanfrage >"{{{query}}" gefunden werden."
     },
     transformData: {
         item: função (meu_resultado) {
         //console.log(my_result);
         //console.log(my_result._highlightResult.body_html_safe.value);
         if (my_result["variant_title"] == 'Título por defeito'){
             my_result["variant_title"] = ";
         }
         além disso
         {
             my_result["variant_title"] = ' :: ' + my_result["variant_title"];
         }
         //my_result["body_html_safe"] = my_result["body_html_safe"].substring(0,175) + '...';
         // NÃO queremos multilinha, queremos igualar o final REAL da corda. /m coincidiria no final da linha...
         var pattern_a = /(.*?)(]*)?$/i;
         var pattern_b = /[^<]+$/i;
        
         // fazer o primeiro grupo combinado - o que exclui o segundo jogo.
         var body_string = my_result._highlightResult.body_html_safe.value.substring(0,175).replace(pattern_a, "$1″);
        
         if (pattern_b.test(body_string)){
             body_string = body_string + "
"
         }
         //pesquisa para pi 3 b+
         //identificação do produto https://buyzero.de/products/budget-kit-raspberry-pi-3-model-b?variant=698066665499
         my_result._highlightResult.body_html_safe.value = body_string + '...';
        
         my_result["product_link"] = "https://buyzero.de/products/” + my_result["handle"] + "?variant=" + my_result["id"];
         devolver o meu_resultado;
         }
     }
   })
);

O container para colocar a saída é selecionado como '#aj-search-results', o template para renderizar os resultados é selecionado aqui: item: document.getElementById('aj-hit-template').innerHTML.

Eu assumo que eles colocaram isso em uma tag , porque o conteúdo não é renderizado como HTML pelo navegador.

Para o vazio, nós apenas passamos uma string como modelo.

Realmente simples até agora, certo?

A seguir usamos transformData para preparar uma versão resumida do corpo de texto do seu produto e outras variáveis passadas para o modelo de sucesso discutido anteriormente.

Porque introduzimos 's na saída da pesquisa - usando o destaque automático da Algolia - precisamos encurtar o texto de uma forma segura. Eu preparei minhas próprias expressões regulares para isso, no meu código de exemplo.

Se houver uma declaração incompleta começando com ), ela é cortada a partir da saída.

Se houver uma tag sem a correspondente tag para fechá-la, nós a adicionamos.

O link do produto é construído obtendo o cabo, e definindo a id como a variante.

Adicionando paginação

adicionar widgets adicionais é fácil:

// Adicione isto depois das outras chamadas search.addWidget()
search.addWidget(
   instantsearch.widgets.pagination({
     contentor: '#aj-paginação de pesquisa',
     render: function(my_obj){
         console.log("render");
         console.log(my_obj);
     },
     getConfiguration: function(my_obj){
         console.log("getConfiguration");
         console.log(my_obj);
     }
   })
);

você não quer a saída do log do console... Eu estava usando isso para depurar, e aparentemente esqueci de tirá-lo. Desculpa. Eu sou humano.

Mais uma vez, o contentor de saída do widget está definido. #aj-paginação de pesquisa'.

Você realmente não precisa de mais nada para a paginação funcionar - monte o widget, e estilo - você vai ser bom.

Faceting

Com o faceting o seu utilizador pode refinar a sua pesquisa:

// Faceting
search.addWidget(
   instantsearch.widgets.refinementList({
     contentor: '#aj-facet-brand',
     atributeName: "fornecedor",
     operador: "ou",
     limite: 5,
     MostrarMais: verdade,
     cssClasses: {
         cabeçalho: 'aj-refine-header',
         contar: 'aj-refine-count'.
     },
     modelos: {
       cabeçalho: 'Marcar / Marca'.
     }
   })
);

  • você precisa olhar os possíveis atributosNomes no seu backend Algolia - ele lhe mostrará as facetas disponíveis para os seus dados (veja a captura de tela abaixo).
  • O limite de 5 não se refere aos resultados da sua pesquisa, mas sim ao limite de entradas que são mostradas pela Algolia para o seu refinamentoLista
  • Os refinamentos disponíveis serão automaticamente actualizados se os outros parâmetros de pesquisa forem alterados (por exemplo, se não houver correspondência para uma marca específica, esta marca não será mostrada)
  • showMore: mostrará um show mais link na parte inferior do widget
  • contar: 'aj-refine-count' - pode dar um pouco de estilo aos resultados da sua pesquisa. Provavelmente mais do que eu usei aqui - consultar a documentação oficial

imagem

Dispositivo Clear Facets

search.addWidget(
   instantsearch.widgets.clearAll({
     recipiente: '#aj-clear-all',
     modelos: {
       ligação: Filtro zurücksetzen / Resetzen
     },
     autoHideContainer: falso,
     clearsQuery: true,
   })
);

usar isto para permitir ao cliente limpar a facetada (ou seja, serão mostrados todos os resultados que correspondem à sua consulta novamente).

Não há necessidade de configurar além disto.

Eu não vou falar sobre os outros widgets - dê uma olhada no meu código se você estiver interessado.

Ligação à caixa de pesquisa

Nós não estamos usando o widget de busca da Algolia, mas nos ligamos a um evento chave acima na entrada do nosso formulário de busca, como este:

    var pb = aj_setup_search();
     //#search_query é a entrada que queremos
     $("#search_query").keyup(function(search) {
       updateSearch(pb);
     });   
}

(discutimos aj_setup_search agora mesmo, foi adicionado aqui para mostrar-lhe de onde vem a pb).

Fazemos isso para que possamos fazer um processamento adicional quando o evento keyup é acionado - escondendo o conteúdo que estávamos exibindo anteriormente na página, e adicionando os resultados da pesquisa, etc.

atualização da funçãoSearch(pb){
     var my_query = $("#search_query").val();
     //$(".main-content").html(my_query);
     if (my_query) {
         $(".main-content").hide();
         $("#megamenu-header-menu2").hide();
         $("#ajr_na").show();
         $("#sc-query").html(my_query);
         $("#aj-arch-container").show();
         pb.search.helper.setQuery(my_query);
         //console.log(search_handle.helper.state);
         pb.ihelper.search();
     }
     senão (
         $("#aj-arch-container").hide();
         $(".main-content").show();
         $("#ajr_na").hide();
         $("#megamenu-header-menu2").show();
     }

}

Nós usamos jQuery para obter o valor do campo de pesquisa. Se não estiver vazio, ocultamos o conteúdo principal que estávamos exibindo antes, e mostramos o recipiente de pesquisa.

Nós definimos sc-query para mostrar ao utilizador que estamos a responder à sua entrada: $("#sc-query").html(my_query);

Finalmente, as partes importantes são estas aqui:

pb.search.helper.setQuery(my_query);
pb.ihelper.search();

como você vê, precisamos usar dois ajudantes diferentes para definir a consulta e executar a pesquisa real. Sim, é assim que tem de ser feito - felizmente encontrei alguém a queixar-se deste comportamento.

Finalmente, se a cadeia de busca estiver vazia (o usuário pressionou Escape, ou apagou, ou nós apagamos, ou o que quer que seja...) nós escondemos a busca, e mostramos o conteúdo principal.

Obrigado por ler

Obrigado pela vossa atenção, espero que isto ajude alguém que queira implementar o instantsearch.js sem usar o widget de pesquisa da Algolia.

Referências

Tampermonkey

Algolia

Bónus