Índice
Campos adicionais (filtros simples, texto rico, medias e html)
Editando variações e opções do produto
$mainData (todos os valores do site)
$productData (todos os valores de um produto)
Filtros nas categorias (preço, variações, texto simples e marcas)
Dados de um filtro por produto
Coletando preços máximos e mínimos
Busca (versões 1 e 2)
Contabilizando visualizações de produtos
Instalação
- A Extensão pode ser instalada via Extensões > Adicionar > Catálogo de Produtos;
- A tela de configurações é aberta para entrada dos valores básicos utilizados no Layout, os quais são (nomes preferenciais em negrito):1. Cor primária: utilizada como variável no Layout var(--primary) e no css escrito no layout para uso em geral em títulos e elementos2. Cor secundária: utilizada como variável no Layout var(--secundary) e no css escrit no layout para em geral em links3. Bloco defaultDeclaration encontrado em Páginas > Blocos, nomes aceitos 'defaultDeclaration', 'defaultDeclarations, default Declarations'4. Bloco do bootstrap em Páginas > Blocos, nomes aceitos 'Bootstrap', 'bootstrapGrid', 'bootstrapgrid', 'BOOTSTRAP GRID'5. Bloco de GTMHEAD em Páginas > Blocos, nomes aceitos 'GTM-HEAD', 'gtmHead', 'GTM Head'6. Bloco do CSS da navbar em Páginas > Blocos, nomes aceitos 'navbarcss', 'navbarCSS', 'NAVBAR CSS'7. Bloco de CSS global do site preferencialmente customCSS em Páginas > Blocos, nomes aceitos 'customcss', 'customCSS', 'custom CSS', 'Custom CSS'8. Bloco com o html do header em Páginas > Blocos, nomes aceitos 'header', 'Header', 'HEADER'9. Bloco com html do footer em Páginas > Blocos, nomes aceitos 'footer', 'Footer', 'FOOTER'10. bloco destinado a JS e scripts, globalScript em Páginas > Blocos, nomes aceitos 'globalscripts', 'globalScripts', 'global scripts', 'GLOBAL SCRIPTS'11. bloco destinado ao gtmBody em Páginas > Blocos, nomes aceitos 'GTM-BODY', 'gtmBody', 'GTM Body'
- É necessário colocar o caminho para o catálogo, acesse Catálogo > ⚙️ Config e coloque o caminho com barra no início e sem barra no fim, por exemplo: /catalogo
- 💡 Todos os links do catálogo são relativos, utilizando o domínio do site ($mainData['siteDomain'], e a extensão de SEO com $mainData['seoOrganizationUrl'] e $mainData['seoBaseHref']) e o caminho do catálogo com $mainData['configPath']
Teste em ambiente local
🏠 O ambiente de teste está na opção Atualizar do catálogo e para utilizá-la não pode ter hospedagem cadastrada em produção.
🖌 Conhecendo o Layout
🚨 Antes de editar o layout, você precisa ter produtos
Os layout são as páginas do catálogo e hoje são dividas da seguinte forma:
Inicial: É a index do catálogo e pode ser acessada como /index após o caminho de configuração, por exemplo: componentes.interago.com.br/catalogo/index
Listas: As listas são as pastas criadas para separar os produtos do catálogo. Cada pasta sempre terá um link com a lista de seus produtos. Os links são criados automaticamente ao subir o site;
🖌 ⛔️ Resetar o Layout: A qualquer momento, é possível resetar o layout para o padrão de instalação (com a tela dos blocos e cores), basta clicar no botão. Cuidado, toda customização em códigos serão perdidas.
Menu: O menu é um fragmento de HTML que pode ser inserido dinamicamente em qualquer outra página para gerar navegação. Por padrão ele está contido na Inicial, todas as categorias e página do produto;
Conteúdo dinâmico: O conteúdo dinâmico possui a URL fixa /q.php, por exemplo: https://site.interago.com.br/catalogo/q.phpEssa página é o único item data-driven (que consulta o banco do catálogo de produtos);
Página do produto: A página para exibição do item do produto em si;
Resumo das páginas que o catálogo terá:
Inicial: https://site.interago.com.br/catalogo/index
Categorias: https://site.interago.com.br/catalogo/cat/praias
Produto: https://site.interago.com.br/catalogo/item/praia-numero-1-do-catalogo
Busca: https://site.interago.com.br/catalogo/q.php?m=search&q=montanha
📦 Organização dos produtos
A organização dos produtos é um dos itens mais importantes quando falamos de catálogos, uma vez que as pastas cadastradas serão transformadas automaticamente em links. É possível criar pastas dentro de pastas sem um limite específico, basta utilizar as opções que estão em Catálogo.
Todo catálogo tem uma pasta padrão chamada Geral, utilize a opção novo dela para começar a criar suas pastas. A exibição da pasta geral é opcional, assim como adicionar produtos dentro dela. ⚠️ A princípio, deixar ela vazia e ter sua própria organização é melhor.
Campos dos produtos e ➕ Campos adicionais
⚠️ Os produtos são adicionados na pasta que você está vendo, certifique-se de adicioná-los na pasta correta.
O cadastro do produto possui 3 níveis de campos:
NÍVEL 1 - cadastramento simples
Campos do cadastro de produtos: Os campos padrão que todo produto precisa: Título, descrição, imagem principal. Para os sites que focam no link building e vitrines mais simples estes campos são suficientes. Estes campos são os primeiros do cadastro de um novo produto.Ainda no cadastro de produtos, você pode clicar em campos adicionais para adicionar preço, peso, marca, SKU, GTIN, MPN e nome de grupo. Os campos adicionais são focados em e-commerce e organização avançada.
Marca: O Interago organiza as marcas de forma descritiva para as buscas e listas adicionais, cadastre as marcas dos produtos sempre da mesma forma para otimizar essa função.
Grupo: O Interago também pode gerar listas de produtos de um mesmo grupo, basta que todos estejam cadastrados da mesma forma, por exemplo, vários produtos com o Grupo "PC GAMER" podem ser listados juntos.
Uma vez que o produto está cadastro, basta clicar na lista para abrir a edição avançada.
NÍVEL 2: Edição padrão dos produtos
Na edição do produto, além de realizar as edições do cadastro é possível alterar a pasta onde está cadastrado e adicionar outras pastas para exibição do produto, conforme a imagem abaixo:
Neste exemplo acima o produto será exibido em Google Ads que é sua pasta principal e a pasta adicional Waze.
NÍVEL 3: Campos adicionais (filtros)
Os campos adicionais são divididos em 4 tipos, os quais são:
📝 Simples: Campos de texto para valores numéricos ou pequenos textos. O texto simples cria filtros de busca e comparação dos produtos, além disso, podem ser listados nas listas do produto, gerando visualizações muito mais detalhadas. Veja o exemplo abaixo de aplicação:
Todas as informações dentro das caixas rosas são filtros. Os campos são cadastros em + Campos e automaticamente aparecem para cada produto para receber seus valores. Os valores de campo simples são compostos por Nome e Valor, onde o nome pode ser diferente do nome de criação.
Os demais campos de Texto Rico, HTML e Medias são invocados somente dentro da página do produto para edição avançada.
⚠️ É muito importante ter a organização completa do produto antes de avançar para o cadastramento, edição de layout e publicação. Por exemplo:
Um site de imóveis precisa que os produtos tenha um carrossel, informações sobre preço, Tipos de imóveis, Quartos, Garagem, Suítes, Área, Cidades e vai querer adicionar um vídeo de Youtube para cada produto. Este catálogo pode ser dividido assim:
Produto padrão: Título, imagem da lista e o Preço;
Pastas: Tipos de imóveis (lotes, barracão, casas...)
Campos de texto simples: Quartos (número), Garagem (sim/não), Suíte (número), Área (número), Cidade (texto);
Campo de Medias: Subir várias fotos para o produto;
Campo de HTML: Subir o player do Youtube de forma responsiva;
NÍVEL 4: Variações e opções por produto
As variações e demais opções são usadas para ter vários produtos em apenas um, por exemplo: uma tv com opções 110V e 220V podem ser um produto apenas, mas com as duas opções.
Para acessar as variações e opções é necessário editar o produto. O produto com variação aparece de forma diferente na lista, conforme a imagem:
As variações podem ser de multiplas escolhas opcionais ou de uma escolha obrigatória para continuar.
É necessário cadastrar a variação para depois cadastrar suas opções. As opções podem conter outras opções, assim como é possível trocar sua ordem arrastando-as.
Ao criar uma variação obrigatória, o visitante terá que escolher as opções até o fim para adicionar o produto na sacola.
⚠️ Os produtos com variações obrigatórios tem seu SKU atualizado automaticamente para as últimas opções possíveis. É possível alterar estes SKUs manualmente.
As opções representadas por um cículo são de uma escolha e as que são representadas por um quadrado são múltiplas escolhas.
Para detalhes de layout e codificação, veja Códigos da Variação e Opções
🐘 Chamando valores para o layout
O layout é editado com PHP, retornando valores em texto, arrays e JSON, dependendo do campo. Abaixo, as funções para compor o layout de acordo com a necessidade de cada cliente.
💡As funções (e caso precise coletar outros dados e criar novas) estão em App/Extensions/5/compile/assets/getData.php
Retornar conteúdo de Bloco do Interago (Páginas)
getBlockData(38);
onde 38 é o id do Bloco; Retorna o HTML de conteúdo do bloco
Retornar informações do site
getMainData();
é invocada por padrão em todas as páginas do layout e contém um Array com as informações:
return $mainData = array(
"siteId" => $siteId,
"siteDomain" => $siteDomain,
"siteName" => $siteName,
"siteDomainToken" => my_simple_crypt($siteDomain),
"configPath" => $configPath,
"configHead" => $configHead,
"configBody" => $configBody,
"seoAuthor" => $seoAuthor,
"seoCoordinates" => $seoCoordinates,
"seoState" => $seoState,
"seoRegion" => $seoRegion,
"seoBaseHref" => $seoBaseHref,
"seoCountry" => $seoCountry,
"seoOrganizationName" => $seoOrganizationName,
"seoOrganizationUrl" => $seoOrganizationUrl,
"seoOrganizationLogo" => $seoOrganizationLogo,
"seoOrganizationLogoWidth" => $seoOrganizationLogoWidth,
"seoOrganizationLogoHeight" => $seoOrganizationLogoHeight,
"seoOrganizationPostalCode" => $seoOrganizationPostalCode,
"seoOrganizationAddress" => $seoOrganizationAddress,
"seoOrganizationHoursWeek" => $seoOrganizationHoursWeek,
"seoOrganizationHoursWeekend" => $seoOrganizationHoursWeekend,
"seoOrganizationPhone" => $seoOrganizationPhone
);
return $productData = array(
"productId" => $productId,
"productType" => $productType,
"productTitle" => $productTitle,
"productDescription" => $productDescription,
"productUrl" => $productUrl,
"productImg" => $productImg,
"productStock" => $productStock,
"productPrice" => $productPrice,
"productStockQtd" => $productStockQtd,
"productPreOrderDays" => $productPreOrderDays,
"productPreOrderFixedDate" => $productPreOrderFixedDate,
"brandName" => $brandName,
"productSKU" => $productSKU,
"productGTIN" => $productGTIN,
"productMPN" => $productMPN,
"productWeight" => $productWeight,
"productCondition" => $productCondition, "productStatus" => $productStatus,
"categoryId" => $categoryId,
"brandName" => $brandName,
"brandUrl" => $brandUrl,
"brandDescription" => $brandDescription,
"brandQtd" => $brandQtd,
"brandImg" => $brandImg,
"visits"=> $visits,
"additionalCats" => $additionalCatIds
);
//additional categories check array
if(!empty($productData['additionalCats'])) {
//foreach additional categorycategory
foreach($productData['additionalCats'] as $v) {
$additionalCatInfo = getCategoryData($v);
//category data array
//return $categoryData = array(
"categoryId" => $categoryId,
"categoryName" => $categoryName,
"categoryImg" => $categoryImg,
"categoryDescription" => $categoryDescription,
"categoryParentId" => $categoryParentId,
"categoryUrl" => $categoryUrl
);
//sample output
$item .= $additionalCatInfo['categoryName'].'<br />';
}
}
function listCustomProducts($websiteId, $category = 0, $min = 0, $max=30, $stock=0, $brand = 0, $excludeProduct = 0, $filters='', $medias='', $description=false, $orderBy='', $addAdditionalCatdsIds=false, $showBrand=false, $showChildren=false, $getShippingInfo=false)
- $websiteId é o Id do website no Interago
- $category: Utilize 0 para listar produtos de qualquer categoria ou o número da categoria (fica ao lado da pasta no catálogo) para listar produtos de uma categoria específica
- $min = 0; Iniciar a lista pelo primeiro produto;
- $max = 30; tamanho da lista, produtos simples podem ser até 500 que está ok;
- $stock = 0 é se o produto está diponível (ainda não utilizado);
- $brand: Id da marca para criar listas por marcas (ainda não utilizado);
- $excludeProduct: Excluir um produto específico pelo id, por exemplo, na visualização do produto, excluir ele mesmo;
- $filters: Selecionar os filtros que deseja colocar os valores, é uma string no formato "1,12,30", por exemplo, irá listar os valores dos campos simples 1, 12 e 30;
- $medias= permitem trazer o filtro um específico filtro de imagens; é preciso infromar o Id do filtro. Objetos do JSON -> imagem_n_pos, media (url), position, type;
- $description = setar true para chamar a descrição do produto na lista. no json = description;
- orderBy = SQL para ordenar, pode-se usar as colunas: productPrice, productTitle, productSKU com ASC ou DESC. O padrão é productId DESC;
- addAdditionalCatdsIds = padrão falso, carrega um vetor com todas as categorias adicionais do produto;
- showBrand = padrão falseo, carrega o nome da marca; caso não tenha marca ou é falso a string vem vazia;
- showChildren = se tiver uma $category nos parâmetros, chama os produtos das categorias filho desta categoria
- getShippingInfo = Para trazer informações de medidas de transporte para conseguir adicionar os itens no carrinho sem precisar entrar na página interna (precisa colocar verificação do campo "variations" trazido junto, para não habilitar este botão de carrinho em itens com variação)
O retorno dessa função é um JSON.
Ordenando os produtos com quantidade de visitas
O parâmetro "visits" é um dos itens do produto, assim como seu id, title, url, img, brandName, price... e muitos outros. Como usar a função para ordernar por visitas
/* $websiteId, $category = 0, $min = 0, $max=30, $stock=0, $brand = 0, $excludeProduct = 0, $filters='', $medias='', $description=false, $orderBy='', $addAdditionalCatsIds=false, $showBrand=false, $showChildren=false */
$productListData = listCustomProducts($mainData['siteId'], $categoryData['categoryId'], 0, 250, 0, 0, 0, '', '', false, 'productanalyticsViews DESC', false, false, false);
Exemplo prático de uso da função na Castro Imóveis:
//chamada da função no layout de Listas, chama o Id da lista, lista 250 itens e usa os filtros 20, 34, 35, 36 e 37
$productListData = listCustomProducts($mainData['siteId'], $categoryData['categoryId'], 0, 250, 0, 0, 0, "20,34,35,36,37");
//checagem se o JSON vem vazio, ou seja, não há produtos
if($productListData[0] != '{}') {
//para cada item do JSON (produto), passar pelos valores
foreach($productListData as $k => $v) {
//Coletar cada item do JSON de cada produto individualmente
$product = json_decode($v, true);
//Variáveis para tratar a imagem e preço
$productImg = '';
$productPrice = '';
//caso o produto não tenha imagem (vazio), pegar uma imagem padrão
$product['img'] == '' ? $productImg = 'https://cdn.interago.com.br/img/png/w_0_q_8/1/mc/cdn//productGeneric' : $productImg = $product['img'];
//opcional para redimensionar a imagem no interago
//$productImg = str_replace('w_0_', 'w_200_', $productImg);
//tratamento do preço
$product['price'] == '0.00' ? $productPrice = '' : $productPrice = $product['price'];
//exibição do preço (caso queira)
if($productPrice != '') {
$productPrice = '<small>R$ </small>'.$productPrice;
$productPrice = str_replace('.', ',', $productPrice);
}
// Trazer valores de um campo simples de filtro
$renderFilter = '';
$tipoImovel = '';
// Localização
$filterKey = "37";
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '') {
$localizacaoImovel = '<p class="endereco"><img src="https://www.interago.com.br/App/Sites/97/mc/Icones/Grupo de máscara 3.svg" width="15" height="15" alt="ícone endereço" loading="lazy"> '.$product[$filterKey]["filterValue"].'</p>';
}
/* $renderFilter .= $product[$filterKey]["filterKey"];
$renderFilter .= $product[$filterKey]["filterValue"];
$renderFilter .= $product[$filterKey]["filterSearchKey"];
$renderFilter .= $product[$filterKey]["filterSearchValue"]; */
}
// Filtros
// Tipo do imovel
$filterKey = "34";
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '') {
$tipoImovel = '<p class="tipoImovel">'.$product[$filterKey]["filterValue"].'</p>';
}
/* $renderFilter .= $product[$filterKey]["filterKey"];
$renderFilter .= $product[$filterKey]["filterValue"];
$renderFilter .= $product[$filterKey]["filterSearchKey"];
$renderFilter .= $product[$filterKey]["filterSearchValue"]; */
}
// Complemento
switch ($categoryData['categoryName']) {
case 'Imóveis':
$complementoImovel = '<p class="complementoImovel">Imóvel</p>';
$compCard = 'compImovel';
break;
case 'Loteamento':
$complementoImovel = '<p class="complementoImovel">Loteamento</p>';
$compCard = 'compLoteamento';
break;
default:
$complementoImovel = '<p class="complementoImovel">Imóvel</p>';
$compCard = 'compImovel';
break;
}
// -------------- Detalhes ---------------
// Área
$filterKey = "20";
$areaImovel = '';
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '' && $product[$filterKey]["filterValue"] > 0) {
$areaImovel = '<p><img src="https://www.interago.com.br/App/Sites/97/mc/Icones/Empreendimentos/Grupo de máscara 55.svg" width="15" height="15" alt="ícone area" loading="lazy"> '.$product[$filterKey]["filterValue"].'</p>';
}
}
// Quartos
$filterKey = "35";
$quartosImovel = '';
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '' && $product[$filterKey]["filterValue"] > 0) {
$quartosImovel = '<p><img src="https://www.interago.com.br/App/Sites/97/mc/Icones/Empreendimentos/Grupo de máscara 52.svg" width="15" height="15" alt="ícone quartos" loading="lazy"> '.$product[$filterKey]["filterValue"].' quartos</p>';
}
}
// Banheiros
$filterKey = "36";
$banheirosImovel = '';
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '' && $product[$filterKey]["filterValue"] > 0) {
$banheirosImovel = '<p><img src="https://www.interago.com.br/App/Sites/97/mc/Icones/Empreendimentos/Grupo de máscara 53.svg" width="15" height="15" alt="ícone banheiro" loading="lazy"> '.$product[$filterKey]["filterValue"].' banheiros</p>';
}
}
//contatenação das variáveis para faze o mix no HTML
$list .= '
<div class="col-12 col-lg-4 '.$compCard.'">
<a href="imoveis/item/'.$product['url'].'" class="cardEmpreendimento">
<img src="'.$productImg.'" alt="Imagem do imóvel '.$product['title'].'" title="'.$product['title'].'" class="imagemImovel" loading="lazy"/>
<div class="filtros">
'.$tipoImovel.$complementoImovel.'
</div>
<div class="txtEmpreendimento">
'.$localizacaoImovel.'
<h3>'.$product['title'].'</h3>
<div class="detalhesImovel">
'.$areaImovel.$quartosImovel.$banheirosImovel.'
</div>
<p>'.$renderFilter.'</p>
<button class="btn btnPrimary">Conferir imóvel</button>
</div>
</a>
</div><!-- col-lg-4 -->
';
}
}
else { //não há produtos nessa categoria
$list .= '<div class="col-12"><h3>Nenhum produto aqui 😞</h3></div>';
}
Exemplo de código para coletar na lista o conteúdo de filtros de Texto Rico
$filterKey = "87";
if(array_key_exists($filterKey, $product)) {
if($product[$filterKey]["filterValue"] != '') {
$renderFilter .= htmlspecialchars_decode($product[$filterKey]["filterValue"]);
}
}
Como o valor do campo de texto rico está em HTML, é necessário utilizar o htmlspecialchars_decode para impressão formatada.
Exemplo de código para coletar o id das categorias adicionais
//additional categories
if(array_key_exists('additionalCatsIds', $product)) {
foreach($product['additionalCatsIds'] as $catId) {
$list .= $catId;
}
}
Retornando as categorias
getMenuData()
<?php
$menu = '';
$menuControl = [];
$menu .= '
<div class="menuToogle" id="catalogToggleButton" style="display:none;"><a class="subTagItemList" style="width:100%;"><span id="menuToogleLabel">+ Menu</span></a></div>
<div class="menu" id="catalogMenu" style="display:none;"><ul class="menuList" id="catalogMenuList">';
foreach($menuData as $k => $v) {
$menuItem = json_decode($v, true);
if($menuItem['qtd'] != 0) { //display only categories with products
$menuItem['categoryUrl'] == "0" ? $url = 'index' : $url = substr($menuItem['categoryUrl'], 1);
$menu .= '<li class="menuItem" cat="'.$menuItem['categoryId'].'" parent="'.$menuItem['categoryParentId'].'" id="item_'.$menuItem['categoryId'].'"><a href="'.$url.'">'.$menuItem['categoryName'].'<span class="menuItemQtd">'.$menuItem['qtd'].'</span></a></li>';
}
}
$menu .= '</ul></div>';
?>
Adicionado ao menu filtros de preços, variações e filtros de texto simples para a página de categorias
//retorna $catPricesRange[0], $catPricesRange[1], $catPricesRange[2], $catPricesRange[3] com o intervalo de preços máximo e mínimo (4 intervalos)
$catPricesRange = getPriceRangeForProductsInACategory($categoryData['categoryId']);
$catPricesRange = getPriceRangeForProductsInACategory($categoryData['categoryId']);
//price intervals exists?
if($catPricesRange != false) {
$list .= '<div class=""><p>Preços</p><ul class="menuList">';
for($i = 0; $i < count($catPricesRange); $i++) {
$catPricesRange[$i] = floor($catPricesRange[$i]);
}
$list .= '<li class="menuItem"><a href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&priceRange='.$catPricesRange[0].'-'.$catPricesRange[1].'&catName='.$categoryData['categoryName'].'"><small>De R$</small>'.$catPricesRange[0].'<small> a R$</small>'.$catPricesRange[1].'</a></li>';
$list .= '<li class="menuItem"><a href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&priceRange='.$catPricesRange[1].'-'.$catPricesRange[2].'&catName='.$categoryData['categoryName'].'"><small>De R$</small>'.$catPricesRange[1].'<small> a R$</small>'.$catPricesRange[2].'</a></li>';
$list .= '<li class="menuItem"><a href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&priceRange='.$catPricesRange[2].'-'.$catPricesRange[3].'&catName='.$categoryData['categoryName'].'"><small>De R$</small>'.$catPricesRange[2].'<small> a R$</small>'.$catPricesRange[3].'</a></li>';
$list .= '</ul></div>';
}
$simpleTextOpts = getSimpleTextDataOfProductsInACategory($categoryData['categoryId']);
if(count($simpleTextOpts) > 0) {
$list .= '<div class=""><ul class="menuList">';
$simpleTextKey = '';
//create a array to store values
$simpleTextOptsArray = array();
for($i = 0; $i < count($simpleTextOpts); $i++) {
//check if $simpleTextOpts['simpleTextName'] is different from $simpleTextKey, if so, print the simpleTextName
if($simpleTextOpts[$i]['productsimpletextKey'] != $simpleTextKey) {
$simpleTextKey = $simpleTextOpts[$i]['productsimpletextKey'];
$list .= '<p>'.$simpleTextKey.'</p>';
//remove elements from $simpleTextOptsArray
unset($simpleTextOptsArray);
$simpleTextOptsArray = array();
}
//check if $simpleTextOpts[$i]['productsimpletextSearchValue'] all ready exists in $simpleTextOptsArray, if not, add it
if(!in_array($simpleTextOpts[$i]['productsimpletextSearchValue'], $simpleTextOptsArray)) {
array_push($simpleTextOptsArray, $simpleTextOpts[$i]['productsimpletextSearchValue']);
$list .= '<li class="menuItem"><a href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&catName='.$categoryData['categoryName'].'&filtro_'.$simpleTextOpts[$i]['productfilterId'].'_'.$simpleTextOpts[$i]['productsimpletextKey'].'='.$simpleTextOpts[$i]['productsimpletextValue'].'">'.$simpleTextOpts[$i]['productsimpletextValue'].'</a></li>';
}
}
$list .= '</ul></div>';
}
$catVariationOpts = getVariationOptionsForProductsInACategory($categoryData['categoryId']);
if(count($catVariationOpts) > 0) {
$list .= '<div class=""><ul class="menuList">';
$variationName = '';
for($i = 0; $i < count($catVariationOpts); $i++) {
//check if $catVariationOpts['variationName'] is different from $variationName, if so, print the variationName
if($catVariationOpts[$i]['variationName'] != $variationName) {
$variationName = $catVariationOpts[$i]['variationName'];
$list .= '<p>'.$variationName.'</p>';
}
$list .= '<li class="menuItem"><a data-variationoption="" href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&catName='.$categoryData['categoryName'].'&variation_'.$catVariationOpts[$i]['variationoptSearchName'].'">'.$catVariationOpts[$i]['variationoptName'].'</a></li>';
}
$list .= '</ul></div>';
}
$catBrands = getBrandsForProductsInACategory($categoryData['categoryId']);
if(count($catBrands) > 0) {
$list .= '<div class=""><p>Marcas</p><ul class="menuList">';
for($i = 0; $i < count($catBrands); $i ++) {
$list .= '<li class="menuItem"><a data-variationoption="" href="'.$mainData['configPath'].'/q.php?catId='.$categoryData['categoryId'].'&catName='.$categoryData['categoryName'].'&brand_'.$catBrands[$i]['brandId'].'='.$catBrands[$i]['brandName'].'">'.$catBrands[$i]['brandName'].'</a></li>';
}
$list .= '</ul></div>';
}
No layout padrão há uma função de JS para tratar o menu e organizar cada item dentro de seu respectivo pai, segue a função padrão para o HTML acima:
<script>
if (navigator.onLine) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
if(xmlhttp.status == 200){
let data = xmlhttp.responseText;
document.getElementById("loadSideMenu").innerHTML = data;
console.log("menu ok");
//organize menu
let organizeItems = document.getElementsByClassName("menuItem");
for(var i = 0; i < organizeItems.length; i++) {
current = organizeItems[i].getAttribute("cat");
parent = organizeItems[i].getAttribute("parent");
if(parent != 0) {
//organize categories inside parents if exists
//document.getElementById("item_"+parent).appendChild(organizeItems[i]);
}
}
//menu toggle
function menuToggle() {
let catalogToggleButton = document.querySelector("#catalogToggleButton");
let catalogMenu = document.querySelector("#catalogMenu");
let menuToogleLabel = document.querySelector("#menuToogleLabel");
let width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
if(width < 766) {
console.log("mobile");
console.log(catalogToggleButton);
catalogToggleButton.style.display = "block";
catalogMenu.style.display = "none";
catalogToggleButton.addEventListener("click", () => {
if ( catalogMenu.style.display == "" || catalogMenu.style.display == "block" ) {
//hide
console.log("show");
catalogMenu.style.display = "none";
catalogMenu.style.opacity = "0";
menuToogleLabel.innerHTML = "+ Menu";
catalogMenu.classList.remove("menuTransition");
}else{
//show
console.log("hide");
catalogMenu.style.display = "block";
catalogMenu.style.opacity = "1";
menuToogleLabel.innerHTML = "- Menu";
catalogMenu.classList.add("menuTransition");
}
})
}
else {
catalogMenu.style.display = "block";
}
}
menuToggle();
}
}
}
let url = "https://www.interago.com.br/App/Sites/'.$mainData['siteId'].'/imoveis/menu.html?"
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setTimeout = 6000; //6s
xmlhttp.ontimeout = function() {
console.log("🚨 tempo esgotado - impossível enviar");
}
xmlhttp.send();
} else {
console.log("🚨 navegador offline");
}
</script>
Retornar os dados de um filtro por produto
getFilterData($filterId, $productId)
$renderFilter = '';
$simpleTextFilterData = json_decode(getFilterData(3, $productData['productId']), true);
if(!empty($simpleTextFilterData)) {
$renderFilter = $simpleTextFilterData['filterKey'].'<br />';
$renderFilter .= $simpleTextFilterData['filterValue'].'<br />';
$renderFilter .= $simpleTextFilterData['filterSearchKey'].'<br />';
$renderFilter .= $simpleTextFilterData['filterSearchValue'].'<br />';
}
💡 Os dados de filterSearchKey e filterSearchValue são formatados de forma padrão para as buscas serem mais eficazes (são os nomes sem espaço e caracteres especiais, basicamente).
coletando o conteúdo de um texto rico e html
//richtext
$richTextFilterData = getFilterData(4, $productData['productId']);
if($richTextFilterData != '{}') $renderFilter .= $richTextFilterData;
//html
$richTextFilterData = getFilterData(7, $productData['productId']);
if($richTextFilterData != '{}') $renderFilter .= $richTextFilterData;
coletando as informações de medias para fazer o MIX de HTML para a interface
//medias
$richTextFilterData = getFilterData(5, $productData['productId']);
//if($richTextFilterData != '{}') $renderFilter .= $richTextFilterData;
if($richTextFilterData != '{}') {
foreach($richTextFilterData as $k => $v) {
$media = json_decode($v, true);
$renderFilter .= $media['productmediasUrl'].'<br />';
$renderFilter .= $media['productmediasType'].'<br />'; //0 = image; 1 = youtube video
}
}
Coletando informações máxima e mínima de preço
getPriceRangeForSearch()
retorna um JSON com os preços mínimo e máximo dos produtos. Exemplo de uso prático:
$priceJson = getPriceRangeForSearch();
$price = json_decode($priceJson, true);
echo $price['minPrice’];
echo $price['maxPrice’];
Coletando todos os conjuntos de valores de um campo de texto simples
Exemplo: Você possui um atributo Quartos e tem centenas de produtos com 1 quarto, 3 quartos e 5 quartos. Vai retornar um JSON com a quantidade total de produtos para cada valor. (1 quarto = 80 produtos; 3 quartos = 60 produtos; 5 quartos = 12 produtos);
getSimpleTextDataForSearch($filterId)
onde $filterId é o Id do filtro de campo simples cadastrado no site. Retorna um JSON com um item, exemplo de uso populando um select (nesse exemplo não usa o total usado, no exemplo seria $filterItem['qtd']):
//rooms
$roomsJson = getSimpleTextDataForSearch(35);
$rooms = '';
foreach($roomsJson as $k => $v) {
$filterItem = json_decode($v, true);
if($filterItem['value'] != '' && $filterItem['value'] > 0) {
$rooms .= '<option value="'.$filterItem['value'].'">'.$filterItem['value'].'</option>';
}
if($rooms != '') {
$roomsSelect = '<select id="filterRooms" data-id="35" name="filtro_35"><option value="">Quartos</option>'.$rooms.'</select>';
}
}
🔎 Busca
A busca por padrão, como já descrito utiliza uma consulta direta no banco e sempre estará no */q.php
Por padrão a busca utiliza os parâmetros na URL:
- q.php?m=search (método padrão para buscar)
- q.php?m=search&q=termo (q de query, é uma string para consulta no título)
- q.php?m=search&priceRange=1000 (é o preço máximo para os resultados, no exemplo serão listados produtos que custam no máximo R$1000,00)
- q.php?m=search&filtro_ID (exemplo "&filtro_20=10"vai retornar somente os produtos onde o valor do filtro #20 é igual a 10) ; pode utilizar n filtros de campo simples.
Coletando os termos buscados mais importates
É possível fazer a coleta de termos mais buscados utilizando a função:
getSearchData($minQtd = 2, $minSearchTimes = 1, $limit = 100, $customTerm = '')
Ela está aplicada no layout padrão com o seguinte formato:
Exemplo da página de produto:
$searchResults = getSearchData(2, 1, 50, '');
//get total os searchResults
$totalSearchResults = count($searchResults);
if(count($searchResults) > 0) {
$item .= '<section class="sectionBreadcrumb"><div class="container"><div class="row"><div class="col-12 breadcrumbPath"><p> Termos mais buscados 🔎</p>
<ol itemscope itemtype="https://schema.org/BreadcrumbList">';
//iterate over the first 30 keywords
$i = 0;
$limit = 20;
//check if limit is greater than totalSearchResults
if($limit > $totalSearchResults) $limit = $totalSearchResults;
$currentLink = '';
while($i < $limit) {
$currentLink = $mainData['siteDomain'].''.$mainData['configPath'].'/'.$searchResults[$i]['searchUrl'];
//remove double slashes from link
$currentLink = str_replace('//', '/', $currentLink);
$item .= '
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem" typeof="WebPage" style="display:inline-flex; margin-top:0px; padding:5px;">
<a itemprop="item" itemtype="https://schema.org/WebPage" id="Link'.$searchResults[$i]['searchUserQuery'].'" title="Buscar por '.$searchResults[$i]['searchUserQuery'].'" href="https://'.$currentLink.'">
<span itemprop="name">'.$searchResults[$i]['searchUserQuery'].'</span>
</a>
<meta itemprop="position" content="'.$i.'" />
</li>';
$i++;
}
//for items beyond the limit, show links as a dropdown
if($totalSearchResults > $limit) {
$item .= '<button id="dropdownForSearchTermsButton">Mais</button>';
while($i < $totalSearchResults) {
$currentLink = $mainData['siteDomain'].''.$mainData['configPath'].'/'.$searchResults[$i]['searchUrl'];
//remove double slashes from link
$currentLink = str_replace('//', '/', $currentLink);
$item .= '
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem" typeof="WebPage" class="dropdownForSearchTermsMoreItems" style="display:none; margin-top:0px; padding:5px;">
<a itemprop="item" itemtype="https://schema.org/WebPage" id="Link'.$searchResults[$i]['searchUserQuery'].'" title="Buscar por '.$searchResults[$i]['searchUserQuery'].'" href="https://'.$currentLink.'">
<span itemprop="name">'.$searchResults[$i]['searchUserQuery'].'</span>
</a>
<meta itemprop="position" content="'.$i.'" />
</li>';
$i++;
}
$item .= '
<script>
document.getElementById("dropdownForSearchTermsButton").addEventListener("click", function() {
//show all dropdownForSearchTermsMoreItems
let dropdownForSearchTermsMoreItems = document.querySelectorAll(".dropdownForSearchTermsMoreItems");
for(var i = 0; i < dropdownForSearchTermsMoreItems.length; i++) {
dropdownForSearchTermsMoreItems[i].style.display = "inline-flex";
}
//remove
document.getElementById("dropdownForSearchTermsButton").remove();
}, once=true);
</script>';
}
Acesso o site da Castro Imóveis para ver a busca detalhada com filtros: App/Sites/97/CatalogLayoutSettings/data.php
🕊 Facinho né!
O texto acima compreende a versão 2 da busca, com o script
<script src="https://www.interago.com.br/App/Extensions/5/tag/search2.js" wId="999" wD="www.meusite.com.br" st="" limit="0" m="" interval="250" path="/catalogo"></script>
O script atual está na versão 3:
<script src="https://www.interago.com.br/App/Extensions/5/tag/search3.js" wId="999" wD="www.meusite.com.br" st="" limit="0" m="" interval="250" path="/catalogo"></script>
Veja o artigo específico para detalhes das buscas:
Variações e opções
Para obter as variaçõe e opções de um respectivo produto usa-se a função no Layout:
getVariationDataOfAProduct($productData['productId']);
O retorno é um JSON com as variações e opções, respectivamente.
O código abaixo é o padrão para popular a variável $variationHTML com o conteúdo + HTML das variações e opções:
$variationHTML = '';
if($variationData[0] != '{}') {
foreach($variationData as $k => $v) {
$eachVariation = json_decode($v, true);
$vId = $eachVariation['variationId'];
$vName = $eachVariation['variationName'];
$vRequire = $eachVariation['variationRequire'];
$vChoices = $eachVariation['variationChoices'];
$vParentId = $eachVariation['parentId'];
$variationReqsOk = 'false';
//each variation options
$options = $eachVariation['options'];
if(!empty($options)) {
$inputType = '';
$variationHelpMessage = '';
//print select, checkboxes or select one option
if($vChoices == '0' && $vRequire == '1') {
$inputType = 'radio';
$variationHelpMessage = 'Obrigatório escolher';
}
else if($vChoices == 1) {
$inputType = 'checkbox';
$variationHelpMessage = 'Opcional e pode escolher vários';
}
else if($vChoices == 0) {
$inputType = 'radio';
$variationHelpMessage = 'Opcional';
}
//required variations DOM control
if($vRequire == '0') $variationReqsOk = 'true';
$variationHTML .= '
<div class="variationContent" id="variationContent_'.$vId.'" variationReqsOk="'.$variationReqsOk.'" required="'.$vRequire.'">
<p class="variationContentTitle">'.$vName.'<span class="variationContentTitleHelpMessage">'.$variationHelpMessage.'</span></p>
';
foreach($options as $o => $d) {
$optionId = $d['variationoptId'];
$optionName = $d['variationoptName'];
$optionPrice = $d['variationoptPrice'];
$optionWeight = $d['variationoptWeight'];
$optionImage = $d['variationoptImage'];
$optionSKU = $d['variationoptSKU'];
$optionExclusive = $d['variationoptExclusive'];
$optionProductFilterId = $d['productfilterId'];
$optionParentId = $d['parentId'];
$lastChild = $d['lastChild']; $optStock = $d['variationoptstockQtd'];
$skuFromVariation = '';
if($optionImage != '') {
$optionImage = '<img src="'.str_replace("w_0_", "w_200_", $optionImage).'" class="optionImage" alt="Imagem de '.addslashes($optionName).'" title=" Imagem de '.addslashes($optionName).'" loading="lazy"/>';
}
if($d['lastChild'] == 0 && $vRequire == 1) {
$skuFromVariation = 'optionSKU="'.$optionSKU.'"';
}
$optionPrice == '0.00' ? $optionPrice = '' : $optionPrice = $optionPrice;
if($optionPrice != '') {
$optionPrice = '<span class="labelOptionPrice"> . +R$'.str_replace('.', ',', $optionPrice).'</span>';
}
$variationHTML .= '
<div class="variationOptionContent" optId="'.$optionId.'" parentId="'.$optionParentId.'" id="variationOptionContent_'.$optionId.'" variation="'.$vId.'" style="display:none;">
<input type="'.$inputType.'" name="option_'.$vId.'" id="option_'.$optionId.'_'.$optionParentId.'" value="'.$optionId.'" class="optionComponent" parentId="'.$optionParentId.'" variation="'.$vId.'" lastChild="'.$lastChild.'" name="'.addslashes($optionName).'">
<label id="labelOption_'.$optionId.'"class="labelForOption" parentId="'.$optionParentId.'" variation="'.$vId.'" option="'.$optionId.'" for="option_'.$optionId.'_'.$optionParentId.'" '.$skuFromVariation.' price="'.$d['variationoptPrice'].'" weight="'.$optionWeight.'" name="'.$optionName.'">'.$optionImage.$optionName.' '.$optionPrice.'</label>
</div>';
}
$variationHTML .= '</div>';
}
}
}
Estoque das opções
O estoque das variações retornam "0" para quando não há produtos disponívels ou "" (vazio) caso nunca foram preenchidas. É possível criar um código abaixo para exibir ou não as opções:
$optStock = $d['variationoptstockQtd'];
$skuFromVariation = '';
if($optStock == "0" || $optStock == "") {
#not avaliable
}
Para as checagens e carrinho funcionarem corretamente, é necessário adicionar o script ao final da página:
<script type="text/javascript" src="https://www.interago.com.br/App/Extensions/5/tag/variations.js" loading="lazy"></script>
ou seu conteúdo para personalização.
O CSS padrão do template para as variações:
.optionComponent {
opacity:0;
position:absolute;
}
.labelForOption {
padding: 5px;
margin: 1px;
display: inline-flex;
border:2px solid #dedede;
cursor:pointer;
width:100%;
align-items:center;
border-radius:5px;
}
.variationOptionChoosen {
font-weight: bold;
border: #41b1dd 3px solid;
}
.variationContentTitle {
border-radius:5px;
padding:10px;
background-color:#dedede;
}
.variationContentTitleHelpMessage {
display: block;
font-size: 75%;
color: #666;
}
.labelOptionPrice {
font-size:75%;
color:#666;
}
.optionImage {
object-fit: cover;
width: 64px;
height: 64px;
margin-right: 5px;
border-radius: 10px;
}
.variationRequiredAlert::after {
content: "👆🏻 É preciso escolher para continuar...";
}
.optionDetailsItem {
margin:0;
font-size:12px;
}
.variationRequiredAlert {
animation: alertBG 2s ease 0s 1 normal forwards;
}
@keyframes alertBG {
0%,
50%,
100% {
background-color: white;
}
25%,
75% {
background-color: #fffdf3;
}
}
⚠️ É importante que o código esteja funcionando para conversar com o botão de adicionar ao carrinho padrão do Interago, conforme este artigo.
<a class="cartAddProduct cartPopupView" cartitemid="'.$productData['productSKU'].'" cartitemname="'.$productData['productTitle'].'" cartitemimage="'.str_replace('w_0_', 'w_64_', $productImg).'" cartitemlink="'.$mainData['seoBaseHref'].$productData['productUrl'].'" cartitemprice="'.$productData['productPrice'].'" cartaddlimit="5" originalProductPrice="'.$productData['productPrice'].'">Adicionar na sacola</a>
Contabilizando visualizações de produtos
A contabilização é realizada por meio do DOM, onde é necessário o elemento #productItemContent com o atributo data-id contendo o ID do produto. No layout padrão este elemento está na tag main:
<main id="productItemContent" data-id="243356">
A contabilização é feita por meio do script da extensão #1: visits2.js;
Exibindo avaliação de compradores
Para exibir a avaliação de compradores é necessário ter a extensão #13 instalada, pois é por ela que é possível permitir que comentários escritos por usuários sejam enviados para o website e a extensão #7 para envio dos e-mails, pois a avaliação é enviada por e-mail.
❌ Não está no front-end do template padrão
✔️ Está habilitado em todos os paineis
Modificações no frontend:
📜 É necessário inserir o script conforme extensão #13 > Scripts.
Inserir os container onde serão exibidos, conforme:
<!-- média de avaliação e quantidade total -->
<div id="aggregateRatingResume"></div>
<!-- carregamento de notas individuais e comentários -->
<div id="ratingAndCommentsResume"></div>
CSS padrão para exibir as estrelas:
.ratingResumeStar {
display: inline-flex;
width: 18px;
height: 18px;
background-size: contain;
background-image: url(https://www.interago.com.br/App/Sites/416/mc/rating/starRatingEmpty.svg);
}
.resumeActiveRatingStar {
background-image: url(https://www.interago.com.br/App/Sites/416/mc/rating/starRating.svg);
}
.resumeHalfRatingStar {
background-image: url(https://www.interago.com.br/App/Sites/416/mc/rating/starRatingHalf.svg);
}
#aggregateRatingResume {
display:inline-flex;
align-items:center;
}
.ratingResumeQuantity {
font-size:11px;
margin-left:5px;
}
Paz ✌🏻
Você também pode gostar de ler
Guia completo para o catálogo de produtos (Extensão)
Instalação, passo a passo e guia prático para utilizar o catálogo no site dos clientes
Em 14/06/2022 às 13h38 - Atualizado em 11/04/2025 às 13h17
Guia da Extensão #11 Promoções
Uso da extensão que gerencia a exibição de preços, desconto por meios de pagamento, categorias e produtos e cupom (em breve)
Em 04/09/2023 às 10h41 - Atualizado em 12/02/2025 às 09h16
Carrinho de compras cart2.js
Extensão 6 do Interago para habilitar o uso de carrinho de compras ao website
Em 29/11/2022 às 12h54 - Atualizado em 03/02/2025 às 11h54
Buscas e Pesquisas no Catálogo de produtos
Script ativo é o search3.js. Buscas em cache com visualização no painel.
Em 01/03/2023 às 09h23 - Atualizado em 16/12/2024 às 11h48
Extensão #9 Envios e cálculos de frete
Extensão que utiliza a Fretnet, Correios, controle por estados e configurações gerais para controle de envios
Em 23/03/2023 às 20h22 - Atualizado em 15/09/2023 às 09h49
Checkout e Pedidos - Extensão #10
Guia para lojas virtuais utilizarem a extensão de checkout e suas especificações
Em 01/06/2023 às 14h35 - Atualizado em 18/08/2023 às 08h36
Estoque do Catálogo de Produtos - Layout, Uso e Consultas
Como adicionar informações de estoque no layoute realizar consultas assíncronas
Em 13/02/2023 às 14h40 - Atualizado em 07/08/2023 às 22h28
Catálogo de Produtos - Listar Produtos com AJAX
Como gerar listas de produtos diretamente da base de dados por ajax
Em 09/08/2022 às 11h03 - Atualizado em 26/12/2022 às 09h37
001. Catálogo em Lista - Formato Imobiliária
Visual de todas as páginas do catálogo de produtos em formato de lista - Ideal para imobiliárias
Em 29/06/2022 às 11h22 - Atualizado em 16/08/2022 às 09h09