HUSKY aka WOOF
Permite aos clientes restringir um catálogo grande por categoria, atributo, preço, stock e texto, com páginas de filtros que o Google consegue indexar.
Levo um produto desde a primeira especificação até à fila de suporte anos depois. 12 plugins no wordpress.org, um SaaS que transforma uma loja WooCommerce num bot do Telegram, uma extensão para Chrome e aplicações Android.
const realmag777 = { role: ["Senior WordPress & WooCommerce Developer", "Plugins & Products Architect"], inIT: 2006, ownProductsSince: 2012, // first plugin on wordpress.org activeInstalls: 167_000, // sum of wordpress.org counters stack: ["PHP", "WordPress", "WooCommerce", "MySQL", "JavaScript", "Node.js", "HTML5", "CSS3", "Docker", "MCP"],}; export default realmag777;
Projetos
Cada página de projeto lista os problemas resolvidos dentro do produto, agrupados por área. O número de instalações e as classificações vêm do wordpress.org, onde pode ler o que os utilizadores escrevem: avaliações do HUSKY, avaliações do FOX, avaliações do BEAR.
Permite aos clientes restringir um catálogo grande por categoria, atributo, preço, stock e texto, com páginas de filtros que o Google consegue indexar.
Mostra os preços na moeda do próprio visitante e pode receber o pagamento nela, para que os clientes estrangeiros saibam o que pagam.
Permite à equipa editar milhares de produtos como numa folha de cálculo, com cada alteração reversível, e permite que assistentes de IA o façam em segurança.
Mostra o catálogo como tabelas de produtos ordenáveis e filtráveis, onde os clientes adicionam artigos ao carrinho diretamente a partir de cada linha.
Permite à equipa do site editar, filtrar, exportar e reverter milhares de artigos, páginas e conteúdos personalizados num único ecrã semelhante a uma folha de cálculo.
Os visitantes pesquisam anúncios, artigos ou produtos por várias propriedades em simultâneo, como preço, ano e categoria.
Mostra os preços escritos no conteúdo do site na moeda de cada visitante, sem necessidade de uma loja WooCommerce.
Mostra artigos ou produtos como tabelas ordenáveis e pesquisáveis, que os visitantes podem filtrar e consultar em qualquer dispositivo.
Associe um conjunto de imagens a qualquer artigo e mostre-as como galerias ou sliders em qualquer ponto do site.
Listas pendentes passo a passo, como marca, modelo e geração, guiam os visitantes por um catálogo grande até à página ou ao produto certo.
Uma loja WooCommerce a funcionar como bot do Telegram: os clientes navegavam, enchiam um carrinho e pagavam sem sair da conversa.
Uma extensão para Chrome que escreve o que diz em qualquer campo de texto de qualquer site, com limpeza opcional por IA.
Um cronómetro Android offline com tempos de volta, que continua a contar corretamente mesmo com a aplicação em segundo plano.
Um leitor que mostra um texto uma palavra de cada vez ao ritmo escolhido e lembra-se de onde parou.
Empresas como bolhas num gráfico de quadrantes que se movem quando os pesos do modelo mudam.
Recolha de eventos, agregação e relatórios com gráficos dentro da administração do WordPress.
Um cliente subscreve uma consulta de filtro e recebe um e-mail quando surgem novos produtos correspondentes.
Um PDF formatado com todos os automóveis do conjunto de resultados atual de um catálogo de veículos.
O que foi resolvido · 14 produtos
Escolha um produto. Cada separador é uma área do seu trabalho e começa com o que oferece ao proprietário, em palavras simples. Abaixo está a parte de engenharia para a sua equipa técnica: o problema e como foi resolvido, retirado do código-fonte. Abra uma linha para ver os detalhes.
o que foi resolvido · escolha um projeto
O que ofereceAs páginas filtradas obtêm endereços limpos e estáveis que os motores de pesquisa podem indexar. O proprietário decide que páginas de filtro aparecem no Google e com que título.
Intercetar a interpretação do pedido, retirar o segmento do filtro, deixar o WordPress corresponder ao resto e reconstruir o estado do filtro a partir do segmento, com uma codificação fixa e regras de índice por profundidade.
Um link de filtro é o URL do arquivo mais o slug do filtro (swoof por omissão) e um segmento por filtro: /product-category/shoes/swoof/color-red-and-blue/size-xl/. O plugin não regista regras de reescrita. url_process() corre em do_parse_request no front end e retorna de imediato, a menos que get_search_request() encontre /<slug>/ no caminho. Toma o segmento do filtro até /page/, ? ou #, remove-o e faz corresponder o restante (/product-category/shoes/ ou /shop/page/2) a $wp_rewrite->wp_rewrite_rules() com código copiado de WP::parse_request(): regras de página verbosas, variáveis de consulta públicas e privadas, tipos de conteúdo visíveis, taxonomias não consultáveis, wp_resolve_numeric_slug_conflicts() e o filtro request. Depois chama query_posts(), handle_404() e register_globals() (a ação parse_request antes do WordPress 6.0) e devolve false, para que o núcleo não volte a interpretar o URL.
parse_url_query() divide o segmento por '/' e faz corresponder cada parte ao mapa de nomes de get_all_items(): slugs de atributos sem pa_, slugs de taxonomias traduzidos pelo WPML, price e as palavras fixas instock, onsale, featured, backorder_not_in. -and- e -or- passam a vírgulas, -to- a um separador de intervalo, + a um espaço; price-10-to-50 passa a min_price e max_price. add_request() junta o resultado através do filtro woof_get_request_data, de modo que get_request_data() devolve o mesmo array que para uma query string ?swoof=1&pa_color=red. Na consulta principal, parse_query() define então post_type product, marca a consulta como arquivo de tipo de conteúdo e acrescenta as meta queries, e tax_query() em woocommerce_product_query_tax_query substitui as entradas do WooCommerce para as mesmas taxonomias pela tax query do plugin.
Como o restante é encaminhado pelas regras existentes, a base da loja, a base das categorias de produto e a paginação dos arquivos continuam a funcionar sem novas regras: /page/N/ é cortado antes de o segmento do filtro ser localizado e permanece no caminho encaminhado. parse_query() desativa is_tax nas páginas de filtro, pelo que a categoria atual é recuperada a partir do último segmento do URL limpo (get_term_from_cleared_url()). Quando a página da loja é também a página inicial, a correção de redirect_canonical abaixo impede o WooCommerce de redirecionar o URL do filtro para /.
Para um URL que corresponde a uma regra SEO, meta_head() imprime o canónico: o URL do filtro sem query string, se o estado for indexável, com os canónicos do Yoast e do SEOPress desativados; caso contrário, o URL cortado no slug do filtro, que é o arquivo simples. Com o Yoast SEO, sitemap_index() em wpseo_sitemap_index acrescenta os URLs que um administrador lista numa textarea das definições, um por linha; a build premium escapa-os com esc_url_raw() e esc_xml().
woof_get_submit_link() em url_parser.js ordena os filtros ativos por chave e escreve cada um como <name>-<values>, com ',' como -and-, um separador de intervalo como -to- e espaços como +. O preço passa a price-<min>-to-<max>; em stock, em promoção, em destaque e backorder passam a palavras fixas. parse_url_query() inverte o mapeamento.
Por causa da ordenação, escolher primeiro a cor e depois o tamanho dá o mesmo caminho que o inverso. Os valores dentro de um mesmo filtro são escritos pela ordem em que foram selecionados.
Os nomes de URL perdem o prefixo pa_, pelo que um atributo e uma chave meta podem produzir o mesmo nome, e uma entrada do mapa esconderia a outra. resolve_seo_key_conflict() dá o nome curto à taxonomia registada, independentemente da ordem dos filtros nas definições, para que os URLs existentes continuem válidos, e deriva um nome para o outro filtro a partir da sua chave real, acrescentando um sufixo numérico se necessário. Os slugs de taxonomias traduzidos pelo WPML são resolvidos antes deste passo.
get_request_data() é chamado a partir de cada consulta de recontagem e, com URLs SEO, cada chamada passa por woof_get_request_data até parse_url_query(). Com Dynamic Recount e Hide Empty (premium), uma página pode fazer mais de mil destas chamadas, pelo que o resultado da interpretação é guardado em cache por URL.
A cache só é ativada depois de wp_loaded, para que uma chamada feita antes de as taxonomias e as definições existirem não possa fixar um mapa de nomes incompleto durante o resto do pedido.
WOOF_SEO conta os filtros ativos. Acima de index_deep (2 por omissão), a página recebe a definição 'Disable page indexing' (sim por omissão, ou seja, noindex,nofollow através de wp_robots) e as regras não são verificadas. Até esse valor, uma regra correspondente torna a página indexável. As regras são padrões de URL com marcadores {any} compilados para expressões regulares, cada uma com título, meta descrição, H1 e texto SEO que podem incluir os nomes dos termos selecionados, e são guardadas por idioma. As etiquetas canónicas só são impressas para URLs que correspondem a uma regra.
Na build premium, preg_match corre sob um gestor de erros temporário, de modo que uma regra cujo URL não é uma expressão válida é ignorada e listada num aviso de administração, e uma regra vazia é ignorada. A edição gratuita usa apenas as duas primeiras regras.
Quando a página da loja é também a página inicial estática, o WooCommerce 11.0.0 define-a como o objeto consultado nos arquivos de produtos. redirect_canonical() passa então a tratar /swoof/... como uma cópia não canónica da página inicial e redireciona para /, perdendo todos os filtros. fix_front_page_shop_canonical() devolve false apenas quando a página inicial é a página da loja, o caminho contém o slug do filtro e o destino do redirecionamento é o URL da página inicial, de modo que a normalização de barras e slugs continua a funcionar em todos os outros casos.
O que ofereceCada opção do filtro mostra quantos produtos devolverá, pelo que os compradores evitam becos sem saída. As contagens ficam em cache, por isso a loja mantém-se rápida em catálogos grandes.
As contagens vêm de uma consulta simplificada, só de IDs, que reproduz a semântica do filtro. Os resultados ficam em cache por pedido, numa tabela dedicada e em transients, e o formulário pode ser diferido até o visitante o pedir.
dynamic_count() reconstrói a tax_query para cada termo. Os termos já selecionados não recebem contagem. Em radio e select (single), o termo substitui o valor selecionado da sua taxonomia; em checkbox e multi-select (multi), é acrescentado a esse valor. Os termos da página de categoria atual e da taxonomia indicada no atributo taxonomies do shortcode entram sempre com AND, de modo que as contagens numa página de categoria ficam dentro dessa categoria.
A lógica por taxonomia (OR, AND, NOT IN) definida nas opções, os intervalos de preço e avaliação, as condições meta das extensões, o idioma do WPML e a visibilidade do catálogo são aplicados da mesma forma que na consulta de produtos. As extensões declaram o seu comportamento de recontagem através de html_type_dynamic_recount_behavior, pelo que os tipos de cor, imagem e etiqueta reutilizam este código.
Esconder as opções sem resultados assenta nestas contagens: o termo é contado e ignorado quando a contagem é 0, pelo que não pode ser mais barato do que mostrar contagens. Esta opção é exclusiva da premium; a edição gratuita força-a a desligada nas vistas.
WP_QueryWOOFCounterIn estende WP_Query e substitui set_found_posts(), setup_postdata(), the_post() e have_posts(). A consulta de contagem corre com fields=ids e nopaging, pelo que o MySQL devolve uma lista de IDs, o WordPress não constrói objetos de post e não emite uma segunda consulta FOUND_ROWS. A contagem é o comprimento da lista.
Os filtros posts_clauses de popularidade e avaliação do WooCommerce são removidos antes da consulta de contagem, porque a ordenação não importa para uma contagem e esses filtros acrescentam joins ao SQL.
Com 'cache count data' ativo, WP_QueryWoofCounter calcula o hash do JSON dos argumentos finais da consulta, que já incluem as partes de idioma e visibilidade, e procura o hash em {prefix}woof_query_cache, uma tabela de duas colunas com o hash como chave primária. As escritas usam INSERT ... ON DUPLICATE KEY UPDATE, pelo que duas visualizações de página a escrever a mesma chave em simultâneo não falham. Um site com cache de objetos persistente pode mover as contagens para wp_cache_* através do filtro woof_use_wp_cache.
Não há maneira barata de saber quais as contagens em cache afetadas por um produto novo ou editado, pelo que um evento agendado esvazia a tabela inteira no período configurado. Se o utilizador MySQL não tiver o privilégio CREATE, a página de definições imprime o SQL a executar manualmente e mantém a opção desligada.
get_filtered_price() constrói um SELECT MIN/MAX sobre _price, ligado à tax query e meta query atuais. O mesmo intervalo era pedido várias vezes por página (mín. e máx. para cada filtro de preço), pelo que o resultado é memorizado num array estático indexado pelo md5 do SQL. Com 'Optimize price filter' ativo, os resultados vão também para um transient durante um dia, e qualquer woocommerce_update_product apaga-o. O SQL passa por woof_get_filtered_price_query, pelo que um site pode acrescentar dicas de índice.
WOOF_HELPER::get_terms() carrega todos os termos de uma taxonomia com get_categories() e monta a árvore pai-filho em PHP. O resultado é memorizado por pedido e, com 'Cache terms' ativo, guardado num transient cuja chave inclui a taxonomia, hide_empty, os indicadores de profundidade e o idioma atual do WPML ou Polylang, de modo que cada idioma tem a sua árvore em cache.
A limpeza percorre wp_options à procura de _transient_woof_terms_cache_% e apaga cada transient, uma vez que o WordPress não tem eliminação por prefixo para transients.
Com start_filtering_btn=1, o servidor devolve apenas um botão, pelo que não correm consultas de termos no carregamento da página. Ao clicar, front.js envia woof_draw_products com o shortcode de produtos definido como 'woof_nothing': o servidor apresenta o formulário do filtro e nenhum produto, a zona de redesenho é substituída e os widgets são reinicializados. O botão é omitido quando já há uma pesquisa ativa, para que uma página filtrada continue a mostrar a sua seleção.
Esconder o formulário com CSS ou regras de display não poupa nada, porque as contagens são calculadas no servidor antes de o HTML ser enviado. Os tópicos de desempenho no fórum de suporte tiveram muitas vezes de esclarecer este ponto.
O que ofereceO filtro continua a funcionar com o tema da própria loja, as páginas de categoria, produtos variáveis, impostos e moedas, pelo que os compradores nunca veem artigos em tamanhos esgotados.
Ligar-se tarde a parse_query e à consulta de produtos do WooCommerce, restaurar o estado de arquivo que os templates esperam e tratar cada diferença do modelo de dados de forma explícita, por versão ou por tabela.
Quando o slug de pesquisa está no pedido, parse_query() define post_type=product e is_post_type_archive, e limpa is_tax, is_tag, is_home, is_single e is_search. O WooCommerce e o tema apresentam então o ciclo da loja para qualquer URL filtrado. As extensões acrescentam as suas condições meta através de assemble_query_params(), e os operadores por taxonomia vêm do filtro woof_main_query_tax_relations.
Os mesmos hooks não devem tocar nos pedidos REST e Store API. Os handlers retornam cedo em URLs /wp-json/ e parse_query é desligado em rest_api_init, pelo que temas de blocos e clientes headless recebem os resultados do próprio WooCommerce.
Um URL de filtro já não é o arquivo do termo, pelo que get_queried_object() deixa de devolver a categoria. Quando o arquivo é apresentado, set_really_current_term() guarda o termo através de WOOF_STORAGE, que o plugin executa em modo transient: um transient por visitante, indexado por um hash do IP do visitante, mantido durante um dia. O JS acrescenta também really_curr_tax=<term_id>-<taxonomy> ao link do filtro, e get_really_current_term() recorre a isso quando nada está guardado. O termo é depois combinado com AND na consulta de produtos, nas consultas de recontagem e na pesquisa de texto. Os pedidos AJAX leem o termo guardado, mas nunca o substituem.
O WooCommerce 3.0 moveu os indicadores de visibilidade, destaque e sem stock do postmeta para a taxonomia product_visibility. product_visibility_not_in() converte os indicadores necessários em cláusulas term_taxonomy_id NOT IN. generate_visibility_keys() acrescenta outofstock quando a loja esconde artigos sem stock; quando a opção 'listen catalog visibility' está ativa, acrescenta também exclude-from-search sempre e exclude-from-catalog fora de uma pesquisa. As lojas mais antigas recebem, em vez disso, uma condição meta _visibility.
As mesmas regras são aplicadas à consulta principal, à consulta do shortcode, às consultas de recontagem, à pesquisa de texto e aos dados do modo turbo. Se uma delas diferir, as contagens e os resultados não coincidem.
Um produto variável conta como em stock se alguma variação estiver, pelo que uma consulta simples por 'em stock + tamanho M' devolve uma camisola cuja variação M está esgotada. Quando o filtro de stock é combinado com filtros de atributos, posts_where() reúne os termos pa_* selecionados, incluindo o termo que está a ser contado durante a recontagem, e executa duas consultas agrupadas em wc_product_attributes_lookup: os produtos pai com uma variação correspondente sem stock e os produtos pai com uma variação em stock. A diferença é acrescentada como ID NOT IN.
Um modo mais antigo, selecionável nas definições do filtro de stock, consulta os posts product_variation por meta de atributo e _stock_status em vez da tabela de consulta. É mais lento e, por omissão, exclui todos os produtos pai que têm uma variação correspondente esgotada; os pais que também têm uma correspondência em stock só são mantidos quando o filtro woof_exclude_existing_variations devolve true.
_price é guardado na moeda base da loja e, em muitas lojas, sem impostos. Se o visitante usa uma moeda do WPML (WCML), assemble_price_params() converte os limites de volta para a moeda base. Se os preços são apresentados com impostos mas guardados sem eles, o imposto incluído da taxa normal é subtraído a ambos os limites. Para o extremo superior do slider, get_max_price() encontra o produto com o preço máximo e pede ao WooCommerce o seu preço com impostos.
Com o FOX (WOOCS), os valores do slider apresentados são convertidos através de woocs_exchange_value, enquanto a consulta mantém números na moeda base.
woof_draw_products() reconstrói $_GET a partir do link que o visitante teria aberto, apresenta [woof_products] e [woof] com esse estado e devolve produtos, formulário e fragmentos adicionais (contagem de resultados, ordenação, paginação) em JSON. front.js substitui cada fragmento, repõe os fragmentos que a resposta não incluía, reinicializa os widgets e chama history.pushState para que o URL possa ser partilhado. onpopstate recarrega a página quando a query string mudou. Um indicador de bloqueio descarta cliques enquanto um pedido está em curso.
O ciclo da loja é envolvido ligando-se a woocommerce_before_shop_loop e woocommerce_after_shop_loop. Os temas que não disparam ambos os hooks quebram o modo AJAX, o que explica uma família de tópicos de suporte com sintomas diferentes e uma só causa.
O que ofereceEm catálogos grandes, a filtragem corre no navegador do comprador em vez de no servidor. Os resultados aparecem depressa e o servidor tem menos carga nas horas de maior movimento.
Pré-calcular um índice JSON plano de produtos e variações, carregá-lo no navegador e executar o filtro como SQL sobre ele com o AlaSQL. O servidor apenas apresenta os IDs correspondentes. Incluído em ambas as edições.
get_data_by_id() escreve ID, título, SKU, autor, pai, estado de stock, os slugs dos termos de todas as taxonomias filtráveis (atributos de variação, no caso das variações), os campos meta configurados e uma lista de pares de preço normal/promocional. Um produto variável guarda um par por filho, para que o navegador possa calcular o seu intervalo de preços com a mesma regra que o WooCommerce usa: o preço promocional só conta quando é inferior ao preço normal.
Os preços são guardados com impostos quando a loja apresenta preços com impostos incluídos, e o FOX é passado para a moeda predefinida antes de os ler, para que o índice fique numa única moeda.
create_data_search_files() recebe um deslocamento, processa 10 IDs de produtos e variações com as regras de visibilidade aplicadas, junta-os ao ficheiro JSON e devolve o deslocamento seguinte; o script de administração repete o ciclo até receber -1. O WPML é passado para o idioma predefinido e cada produto é escrito no ficheiro de cada idioma através do seu ID de tradução. check_id_file() acrescenta o ID do blog em multisite para que os sites não partilhem um ficheiro.
O limite predefinido é de 15,000 registos, ajustável com o filtro woof_turbo_mode_products_limit.
PN_WP_CRON_WOOF_TURBO_MODE guarda o estado do evento (lista completa de IDs, posição, próxima execução) numa opção e corre em init. Cada chamada de process() trata uma fatia de 10 IDs, e uma limitação de 5 segundos guardada em woof_cron_limit_do impede que uma rajada de visualizações de página execute fatias em sequência. As fatias são escritas em data_<id>_temp_<lang>.json; quando a lista se esgota, do_recreate_file() move o ficheiro temporário para cima do ficheiro ativo, e os visitantes mantêm o índice antigo até o novo estar completo.
O custo deste desenho é a desatualização: os produtos adicionados depois da última reconstrução ficam invisíveis para o filtro, e a reconstrução depende do tráfego do site da mesma forma que o WP-Cron.
turbo_mode.js converte os valores atuais numa string WHERE: pertença a taxonomias através de indexOf nos arrays de termos, comparações meta, LIKE para SKU e título, BETWEEN para sliders e datas. Funções AlaSQL personalizadas calculam o preço mínimo e máximo de um produto a partir da sua lista de variações e aplicam a visibilidade do catálogo. Para produtos variáveis, o filtro de stock seleciona primeiro os pais das variações sem stock que correspondem aos outros filtros. A recontagem corre sobre a mesma tabela em memória.
Os IDs resultantes são enviados para woof_draw_products como turbo_mode_ids, e o servidor apresenta uma consulta post__in em vez dos joins do filtro.
O JS reconstrói a lógica do filtro a partir de woof_settings, pelo que precisa de grande parte dessa opção na página. get_public_settings() remove o bloco de estatísticas, que contém as credenciais do MySQL externo, e todas as cron_secret_key, e passa o resto por um filtro para mais remoções. Na build premium, o endpoint de reconstrução exige um nonce e manage_woocommerce.
O que ofereceO proprietário vê o que os compradores realmente filtram e pesquisam, sem tornar a loja mais lenta nem encher a sua base de dados com um registo em crescimento permanente.
Escrever uma pequena linha em bruto por pedido numa tabela de preparação e manter as estatísticas de longo prazo num servidor MySQL separado, exigido pela extensão.
A extensão de estatísticas liga-se a woof_get_request_data, que corre várias vezes por página; um indicador estático limita o registo à primeira chamada, e as chamadas AJAX que não sejam a apresentação de produtos são ignoradas. Apenas as chaves de filtro escolhidas nas definições são mantidas, o pedido é cortado para request_max_deep chaves (5 por omissão) preservando o intervalo de preço, e é calculado o hash em conjunto com o IP e a data.
Uma linha só é inserida se esse hash for novo e o IP tiver menos de user_max_requests linhas (10 por omissão) na tabela de preparação.
A extensão precisa do seu próprio servidor MySQL, indicado nas opções. init_pdo() liga-se a ele com PDO, uma vez que $wpdb não consegue manter uma segunda ligação com outras credenciais. place_statdata_into_db() cria uma tabela por mês com o nome <year>_<month> e insere as linhas com prepared statements.
Os relatórios consultam as tabelas mensais por intervalo de datas, pelo que a base de dados da loja não guarda as estatísticas de longo prazo.
O que ofereceOs compradores encontram produtos por SKU, atributo ou palavras nas descrições das variações. Os clientes registados podem guardar uma pesquisa e ser notificados quando chegarem novos produtos correspondentes.
Construir a cláusula WHERE a partir de fragmentos preparados por palavra, com joins acrescentados só quando necessário, resolver as variações para produtos pai numa consulta separada, limitar o que o endpoint público pode pedir e voltar a executar as pesquisas guardadas a partir de SQL capturado no servidor.
create_where_query() divide a frase em palavras. Para cada palavra, combina com OR os campos de post selecionados e as chaves meta listadas (o SKU é apenas _sku), mais uma correspondência do nome do termo com a frase inteira, e os grupos de palavras são combinados com AND. Um '-' inicial transforma a palavra em NOT LIKE ligado com AND. Os fragmentos passam por $wpdb->prepare().
Os joins de termos e postmeta só são acrescentados em posts_join quando essas opções estão ativas, e posts_groupby elimina as linhas duplicadas que os joins criam.
As variações são posts separados, e a consulta do produto pai não consegue ver _variation_description. Quando a opção está ativa, uma consulta encontra os posts product_variation cuja descrição contém todas as palavras, uma segunda mapeia-os para post_parent, e a cláusula principal passa a (condições das palavras OR ID IN (pais)). A lista de pais pode ser guardada na cache de objetos por lista de palavras.
ajax_search() está aberto a visitantes e pagina a consulta em SQL com max_posts como tamanho da página, pelo que só é carregada uma página de correspondências. Na build premium, max_posts do pedido é limitado entre 1 e o maior valor entre a definição do administrador e 100, que é filtrável. As sugestões respeitam o estado atual do filtro, a página de categoria e a restrição de produtos em promoção.
O filtro de texto constrói a sua própria consulta de pesquisa, pelo que um plugin de pesquisa separado não pode decidir o conjunto de resultados no mesmo pedido; os tópicos de suporte listam o Ivory Search, o Relevanssi e o Advanced Woo Search entre esses conflitos. get_all_ids() aplica primeiro o filtro woof_text_search_ids. Quando um callback devolve um array, por exemplo IDs do SearchWP, esse array é o conjunto de correspondências e o SQL incorporado é ignorado. Ligar um determinado motor exige código personalizado.
A vista do Products Messenger guarda $wp_query->request, o SQL que o WordPress gerou para os resultados filtrados, no armazenamento por visitante do plugin, sob o ID do utilizador. Na subscrição, que exige um utilizador com sessão iniciada, o servidor lê-o de volta desse armazenamento e não do pedido, remove LIMIT, verifica que é um único SELECT sem palavras-chave DML ou DDL, executa-o uma vez para registar uma linha de base de IDs e guarda a subscrição no user meta.
A tarefa agendada volta a executar cada consulta guardada e envia por e-mail apenas os IDs que não estão na linha de base, estendendo depois essa linha de base. Uma subscrição termina por número de mensagens ou por data. O user meta só é atualizado quando wp_mail() tem êxito, pelo que um envio falhado é repetido na execução seguinte.
O que ofereceOs visitantes anónimos não podem usar o filtro para executar código nem aceder a dados ocultos, e as definições guardadas não se perdem nem são sobrescritas quando se fazem alterações.
Tratar cada valor do pedido como dados: permitir apenas shortcodes e templates conhecidos, sanear as definições recursivamente por caminho de chave, exigir capacidades para tudo o que guarda código e juntar as definições em vez de as sobrescrever.
[woof_products custom_tpl=...] é legitimamente devolvido nas chamadas AJAX, pelo que o valor não pode ser nem aceite sem verificação nem descartado. sanitize_custom_tpl() mantém apenas letras, dígitos, '_', '-' e '/', o que remove pontos e sequências de travessia. Um nome apresentado a partir de conteúdo real da página é acrescentado a uma opção de lista de permissões (mantêm-se os últimos 20); durante o AJAX, só são aceites nomes que já estejam nessa lista.
Os caminhos de inclusão construídos a partir de nomes de tipos de vista passam por safe_view_slug(), que rejeita tudo o que não seja um slug simples.
woof_draw_products() recebe da página o texto dos shortcodes de produtos e de formulário para que o resultado AJAX coincida com a chamada original. check_shortcode() constrói get_shortcode_regex() apenas para as tags do plugin ([woof_products] ou [woof], mais os alias do shortcode de produtos do plugin) e mantém a primeira correspondência; tudo o resto na string é descartado antes de do_shortcode().
sanitize_array() percorre a árvore de definições, guarda cada valor sob a sua chave saneada e classifica cada campo pelo nome ou pelo caminho na árvore: o texto das regras SEO como HTML através de wp_kses_post, as descrições como textarea, as chaves usadas em caminhos de inclusão como slugs estritos, tudo o resto como texto simples. As regras por caminho são necessárias porque chaves em profundidade na árvore, como text ou description, são demasiado genéricas para serem listadas globalmente.
A definição 'JavaScript after AJAX' só pode ser alterada por utilizadores com unfiltered_html.
A apresentação AJAX reconstrói $_GET a partir do link da página enviado pelo navegador, e a resposta injeta woof_redraw_elements na página como HTML, pelo que um link forjado não pode fornecer essa chave. Na build premium, a chave é removida do link interpretado. Os fragmentos legítimos (título SEO e H1, contagem de resultados, ordenação) são acrescentados por filtros do lado do servidor, e todos os fragmentos passam por wp_kses antes de serem devolvidos.
A página de definições lista apenas os termos do idioma atual do WPML ou Polylang, pelo que um envio contém cores apenas para esses termos. woof_save_options() junta as entradas guardadas de color, color_img e images_term_* por baixo dos valores submetidos, para que os outros idiomas mantenham as suas.
Um termo traduzido sem cor própria usa o seu original no idioma predefinido, encontrado por get_original_language_term(). Lê o slug diretamente de wp_terms, porque com o ajuste de ID do WPML get_term() pode devolver de novo o termo traduzido.
O que ofereceOs problemas numa loja em produção são encontrados na sua causa real, mesmo quando é o tema, o servidor, uma cache ou outro plugin.
Reproduzir numa instalação limpa ou numa cópia do site, excluir uma camada de cada vez e corrigir onde está a causa: no plugin, para todos, ou com uma alteração dirigida nesse site.
Mesmo um parâmetro sem significado como ?dwdadd=1adw quebrava a página, o que provou que a falha estava no tratamento da query string e não no filtro. A configuração do Nginx inseria um ? a mais depois de php e descartava todos os parâmetros, pelo que o filtro nunca recebia os seus argumentos.
A resposta chegava, mas JSON.parse falhava com um carácter de escape inválido, o que significava que o CDN Mapping do LiteSpeed estava a reescrever URLs dentro dela. Desligar o CDN Mapping repôs a filtragem.
O site carregava o jQuery slim, que não tem módulo AJAX, pelo que o pedido dos resultados filtrados nunca era enviado enquanto o URL mudava do lado do cliente; desativar todos os outros plugins não mudou nada. A build slim vinha com um núcleo do WordPress modificado pelo instalador automático do alojamento; repor o jQuery completo e reinstalar o núcleo resolveu o problema.
woof_slider_meta_query_type para que a conversão SQL possa ser definida como DECIMAL por chave metaO autor do relatório reconstruiu o campo como campo personalizado simples e a falha manteve-se, pelo que o ACF não era a causa; o suporte reproduziu-a. A meta query comparava os valores sem conversão para DECIMAL, e o plugin ganhou o hook woof_slider_meta_query_type, que recebe $type e $key.
pageshow que repõe o bloqueio de envio e o popup ao restaurar do bfcache, incluído nas atualizaçõesAs páginas restauradas da cache de recuo/avanço mantinham woof_submit_link_locked definido e o popup de carregamento aberto. O listener verifica event.persisted ou o tipo de navegação 2 e repõe ambos; a alteração foi incluída no plugin.
Anel interior: stack principal · anel exterior: ferramentas e plataformas
Sobre · stack
Concebo a arquitetura e o modelo de dados, depois escrevo o código, publico-o e dou-lhe suporte. Nenhuma camada fica entregue a alguém que eu não possa verificar.
Trabalho à medida
Trabalho personalizado para clientes, geralmente pessoas que começaram com um dos meus plugins. Nomes e sites permanecem privados.
Um grande diretório B2B de fornecedores construído em WordPress.
O mesmo portal WordPress.
Começou como trabalho personalizado para o proprietário de uma loja e foi depois lançado como a extensão Products Messenger para HUSKY e MDTF.
Um catálogo de veículos construído com MDTF, extensão personalizada para um cliente na Alemanha.
Integrado, não acrescentado
Os proprietários obtêm os números na mesma administração onde configuram o plugin.
Cronologia
Apenas os meus próprios produtos. As datas de lançamento são as datas em que cada plugin foi adicionado ao wordpress.org.
Antes de escrever
Descreva a tarefa no formulário abaixo ou por e-mail para realmag777 [at] gmail.com: o que deve ser criado ou alterado e para quando. Se tiver um site de staging, mencione-o: é lá que o trabalho é feito e verificado. Respondo em dois dias úteis com perguntas ou com uma estimativa de prazo e custo. O trabalho começa quando o âmbito estiver acordado.
Uma tarefa claramente descrita recebe uma estimativa fixa para o âmbito acordado. O trabalho em aberto, como encontrar a causa de um problema num site em produção ou o suporte contínuo, é acordado à hora.
Hora da Europa Central (UTC+1, UTC+2 no verão). Escrevo e falo em Inglês, ucraniano e espanhol. A maior parte do trabalho decorre por e-mail e mensagens, pelo que a diferença horária raramente importa.
Sim. Os nomes e sites dos clientes nunca são mostrados aqui, e assino um NDA quando o projeto o exige.
Não. Desenvolvo funcionalidades sobre os meus plugins ou quaisquer outros, trabalho em código escrito por outros programadores e desenho projetos novos de raiz. Com código de terceiros, leio-o primeiro e digo o que encontrei antes de alterar o que quer que seja.
Sozinho. Arquitetura, código, publicação e suporte são meus, pelo que fala com a pessoa que constrói a solução e nada se perde entre pessoas.
Sim, inclusive sob a marca da agência. Escreva quem é e do que precisa.
Por acordo. Fale-me do projeto e do volume que espera, e combinamos antes de o trabalho começar.
Em euros.
Um site de staging, uma cópia do site em produção, com acesso de administrador e a ficheiros, mais uma cópia da base de dados quando a tarefa envolve dados. Se não existir staging, preparo um. As alterações só chegam ao site em produção depois de funcionarem em staging.
A si, depois de o trabalho estar pago.
Os erros no trabalho entregue são corrigidos. Alterações adicionais e suporte podem ser acordados em separado. Os meus próprios plugins têm suporte há mais de dez anos, pelo que a manutenção a longo prazo é o caso normal, não uma exceção.
Contacto
Escreva o que deve ser criado ou alterado e para quando. Respondo em dois dias úteis.
realmag777 [at] gmail.com linkedin.com/in/realmag777