Lingua

Contattami

Plugin per WooCommerce · dal 2014 · aka WOOF

HUSKY

Un filtro prodotti a faccette per WooCommerce: tassonomie, attributi, prezzo, disponibilità, campi meta e testo, come widget o shortcode, con ricaricamento della pagina o AJAX.

Prima versione
Installazioni attive
80.000+
Valutazione
4.6 / 5 (336)Leggi le recensioni
  • PHP
  • WordPress
  • WooCommerce
  • WP_Query
  • WP_Tax_Query
  • WP_Meta_Query
  • MySQL
  • Transient
  • Object cache
  • jQuery
  • AlaSQL
  • PDO
  • WPML
  • Polylang
Vedi su wordpress.org wordpress.org

Chi sono

HUSKY filtra i prodotti WooCommerce per categorie, attributi, tag, prezzo, stato di disponibilità, valutazione, autore, SKU, campi meta personalizzati e testo. È su wordpress.org dal 2014. Le edizioni gratuita e premium sono compilate da un'unica base di codice; l'edizione si seleziona con il numero di versione maggiore, e le parti solo premium sono sostituite da stub o limitate nella versione gratuita.

Ogni stato del filtro diventa una query WordPress su wp_posts, wp_postmeta e sulle tabelle dei termini, e i negozi gestiscono decine di migliaia di prodotti e varianti. Mostrare quanti prodotti restituirebbe ogni opzione significa una query in più per ogni termine visibile a ogni visualizzazione di pagina. Prodotti variabili, visibilità del catalogo, imposte e plugin per le valute cambiano ciascuno ciò che si intende per corrispondenza.

Il plugin lavora anche all'interno di una gestione delle richieste che non gli appartiene: analisi delle rewrite di WordPress, query principale e template dei prodotti di WooCommerce, page builder, plugin multilingua e livelli di cache. Gran parte del codice descritto sotto esiste perché uno di questi livelli rendeva l'approccio diretto sbagliato o troppo lento.

HUSKY · filtro prodotti

cosa è stato risolto

ATTIVOdal 2014

URL SEO per gli stati del filtro

nel prodotto

Cosa offreLe pagine filtrate ottengono indirizzi puliti e stabili che i motori di ricerca possono indicizzare. Il proprietario decide quali pagine filtrate compaiono su Google e con quale titolo.

Problema
Gli stati del filtro sono query string, che i motori di ricerca ignorano oppure scansionano senza limiti. Gli URL a percorso come /swoof/color-red/size-m/ sono sconosciuti alle regole di rewrite di WordPress ed entrano in conflitto con i redirect canonici.
Soluzione

Intercettare l'analisi della richiesta, rimuovere il segmento del filtro, lasciare che WordPress riconosca il resto e ricostruire lo stato del filtro dal segmento con una codifica fissa e regole di indicizzazione per profondità.

Stack
  • WordPress rewrite API
  • PHP
  • JavaScript
  • Yoast SEO
Attività · 6
/shop/swoof/color-red/size-xl/ non corrisponde ad alcuna regola di rewrite e dà 404Tagliare il segmento del filtro, instradare il resto con le regole di rewrite del core, ricostruire i filtri da esso

Un link del filtro è l'URL dell'archivio più lo slug del filtro (swoof per impostazione predefinita) e un segmento per ogni filtro: /product-category/shoes/swoof/color-red-and-blue/size-xl/. Il plugin non registra regole di rewrite. url_process() viene eseguita su do_parse_request nel front end e termina subito, a meno che get_search_request() non trovi /<slug>/ nel percorso. Prende il segmento del filtro fino a /page/, ? o #, lo rimuove e confronta il resto (/product-category/shoes/ o /shop/page/2) con $wp_rewrite->wp_rewrite_rules() usando codice copiato da WP::parse_request(): regole verbose delle pagine, query var pubbliche e private, post type visualizzabili, tassonomie non interrogabili, wp_resolve_numeric_slug_conflicts() e il filtro request. Poi chiama query_posts(), handle_404() e register_globals() (l'azione parse_request prima di WordPress 6.0) e restituisce false, così il core non analizza di nuovo l'URL.

parse_url_query() divide il segmento per '/' e confronta ogni parte con la mappa dei nomi di get_all_items(): slug degli attributi senza pa_, slug delle tassonomie tradotti da WPML, price e le parole fisse instock, onsale, featured, backorder_not_in. -and- e -or- diventano virgole, -to- un separatore di intervallo, + uno spazio; price-10-to-50 diventa min_price e max_price. add_request() unisce il risultato tramite il filtro woof_get_request_data, così get_request_data() restituisce lo stesso array che si avrebbe con una query string ?swoof=1&pa_color=red. Sulla query principale, parse_query() imposta poi post_type product, segna la query come archivio di post type e aggiunge le meta query, mentre tax_query() su woocommerce_product_query_tax_query sostituisce le voci di WooCommerce per le stesse tassonomie con la tax query del plugin.

Poiché il resto viene instradato dalle regole esistenti, la base dello shop, la base delle categorie prodotto e la paginazione dell'archivio continuano a funzionare senza nuove regole: /page/N/ viene tagliato prima che il segmento del filtro sia individuato e resta nel percorso instradato. parse_query() disattiva is_tax sulle pagine filtrate, perciò la categoria corrente viene recuperata dall'ultimo segmento dell'URL ripulito (get_term_from_cleared_url()). Quando la pagina dello shop è anche la home page, la correzione di redirect_canonical descritta sotto impedisce a WooCommerce di reindirizzare l'URL del filtro a /.

Per un URL che corrisponde a una regola SEO, meta_head() stampa il canonical: l'URL del filtro senza query string se lo stato è indicizzabile, con i canonical di Yoast e SEOPress disattivati, altrimenti l'URL tagliato allo slug del filtro, cioè l'archivio semplice. Con Yoast SEO, sitemap_index() su wpseo_sitemap_index aggiunge gli URL che un amministratore elenca in una textarea delle impostazioni, uno per riga; la versione premium li escapa con esc_url_raw() ed esc_xml().

L'ordine in cui si usano i filtri non deve cambiare l'URLScrivere i filtri in ordine di chiave; replicare la grammatica -and- / -to- / + in PHP e JS

woof_get_submit_link() in url_parser.js ordina i filtri attivi per chiave e scrive ciascuno come <name>-<values>, con ',' come -and-, un separatore di intervallo come -to- e gli spazi come +. Il prezzo diventa price-<min>-to-<max>; disponibile, in offerta, in evidenza e ordinabile in arretrato diventano parole fisse. parse_url_query() inverte la mappatura.

Grazie all'ordinamento, scegliere prima color e poi size dà lo stesso percorso del caso inverso. I valori all'interno di un filtro sono scritti nell'ordine in cui sono stati selezionati.

L'attributo pa_niveau e il campo meta niveau chiedono lo stesso nome nell'URLRilevare le collisioni di nomi: la tassonomia mantiene il nome breve, l'altro ottiene un ripiego univoco

I nomi negli URL perdono il prefisso pa_, perciò un attributo e una chiave meta possono produrre lo stesso nome, e una sola voce della mappa nasconderebbe l'altra. resolve_seo_key_conflict() assegna il nome breve alla tassonomia registrata indipendentemente dall'ordine dei filtri nelle impostazioni, così gli URL esistenti restano validi, e ricava un nome per l'altro filtro dalla sua chiave reale, aggiungendo un suffisso numerico se serve. Gli slug delle tassonomie tradotti da WPML vengono risolti prima di questo passaggio.

Ogni query di conteggio rilegge lo stato del filtro dal percorso dell'URLMemorizzare parse_url_query() per ogni URL, ma solo dopo wp_loaded

get_request_data() viene chiamata da ogni query di conteggio, e con gli URL SEO ogni chiamata passa da woof_get_request_data a parse_url_query(). Con Dynamic Recount e Hide Empty (premium) una sola pagina può generare più di mille chiamate di questo tipo, perciò il risultato dell'analisi viene messo in cache per URL.

La cache viene attivata solo dopo wp_loaded, così una chiamata fatta prima che tassonomie e impostazioni esistano non può congelare una mappa dei nomi incompleta per il resto della richiesta.

Quali pagine filtrate indicizzare, e con quale titolo e metaIndicizzare per profondità e per regole regex con meta per regola; saltare in silenzio i pattern errati

WOOF_SEO conta i filtri attivi. Oltre index_deep (2 per impostazione predefinita) la pagina riceve l'impostazione 'Disable page indexing' (predefinita su sì, quindi noindex,nofollow tramite wp_robots) e le regole non vengono controllate. A quel valore o sotto, una regola corrispondente rende la pagina indicizzabile. Le regole sono pattern di URL con segnaposto {any} compilati in espressioni regolari, ciascuna con titolo, meta description, H1 e testo SEO che possono includere i nomi dei termini selezionati, e sono salvate per lingua. I tag canonical vengono stampati solo per gli URL che corrispondono a una regola.

Nella versione premium, preg_match viene eseguita sotto un error handler temporaneo, così una regola il cui URL non è un'espressione valida viene saltata ed elencata in un avviso di amministrazione, e una regola vuota viene saltata. L'edizione gratuita usa solo le prime due regole.

WooCommerce 11 reindirizzava gli URL dei filtri su una front page che è lo shopAnnullare solo il redirect verso home_url, e solo per gli URL che contengono lo slug del filtro

Quando la pagina dello shop è anche la front page statica, WooCommerce 11.0.0 la imposta come oggetto interrogato negli archivi dei prodotti. redirect_canonical() tratta allora /swoof/... come una copia non canonica della front page e reindirizza a /, perdendo ogni filtro. fix_front_page_shop_canonical() restituisce false solo quando la front page è la pagina dello shop, il percorso contiene lo slug del filtro e la destinazione del redirect è l'URL della home, così la normalizzazione di slash e slug continua a funzionare ovunque altrove.

Conteggio dinamico e cache delle query

nel prodotto

Cosa offreOgni opzione del filtro mostra quanti prodotti restituirà, così gli acquirenti evitano i vicoli ciechi. I conteggi sono in cache, quindi lo shop resta veloce nei cataloghi grandi.

Problema
Ogni opzione del filtro mostra quanti prodotti restituirebbe data la selezione corrente. Significa una query prodotti per ogni termine visibile a ogni visualizzazione di pagina, ed è il costo principale nei cataloghi grandi.
Soluzione

I conteggi vengono da una query ridotta, solo ID, che riproduce la semantica del filtro. I risultati sono messi in cache per richiesta, in una tabella dedicata e nei transient, e il modulo può essere differito fino a quando un visitatore lo richiede.

Stack
  • WP_Query
  • MySQL
  • Transient
  • Object cache
Attività · 6
Il conteggio di un termine deve riflettere il resto della selezione correnteRicostruire la query per termine, inserendo il termine secondo le regole di selezione singola o multipla

dynamic_count() ricostruisce la tax_query per ogni termine. I termini già selezionati non ricevono un conteggio. Per radio e select (single) il termine sostituisce il valore selezionato della sua tassonomia; per checkbox e multi-select (multi) viene aggiunto ad esso. I termini della pagina di categoria corrente e delle tassonomie dell'attributo taxonomies dello shortcode sono sempre messi in AND, così i conteggi in una pagina di categoria restano all'interno di quella categoria.

La logica per tassonomia (OR, AND, NOT IN) dalle impostazioni, gli intervalli di prezzo e valutazione, le condizioni meta delle estensioni, la lingua WPML e la visibilità del catalogo sono applicati allo stesso modo della query dei prodotti. Le estensioni dichiarano il loro comportamento di conteggio tramite html_type_dynamic_recount_behavior, così i tipi color, image e label riutilizzano questo codice.

Nascondere le opzioni senza risultati si basa su questi conteggi: il termine viene contato e saltato quando il conteggio è 0, perciò non può costare meno che mostrare i conteggi. Questa opzione è solo premium; l'edizione gratuita la forza su disattivata nelle viste.

Una query di conteggio non dovrebbe caricare post né eseguire FOUND_ROWSEstendere WP_Query con i metodi found-rows e loop resi no-op, recuperare solo gli ID

WP_QueryWOOFCounterIn estende WP_Query e sovrascrive set_found_posts(), setup_postdata(), the_post() e have_posts(). La query di conteggio gira con fields=ids e nopaging, così MySQL restituisce un elenco di ID, WordPress non costruisce oggetti post e non emette una seconda query FOUND_ROWS. Il conteggio è la lunghezza dell'elenco.

I filtri posts_clauses di popolarità e valutazione di WooCommerce vengono rimossi prima della query di conteggio, perché l'ordinamento non conta per un conteggio e quei filtri aggiungono join all'SQL.

Gli stessi conteggi vengono ricalcolati per ogni visitatore e ogni paginaSalvare i conteggi in una tabella chiave-valore con chiave md5 degli argomenti completi della query, svuotarla via cron

Con 'cache count data' attivo, WP_QueryWoofCounter calcola l'hash del JSON degli argomenti finali della query, che includono già le parti di lingua e visibilità, e cerca l'hash in {prefix}woof_query_cache, una tabella a due colonne con l'hash come chiave primaria. Le scritture usano INSERT ... ON DUPLICATE KEY UPDATE, così due visualizzazioni di pagina che scrivono la stessa chiave nello stesso momento non falliscono. Un sito con una object cache persistente può spostare i conteggi su wp_cache_* tramite il filtro woof_use_wp_cache.

Non esiste un modo economico per individuare quali conteggi in cache sono toccati da un prodotto nuovo o modificato, perciò un evento pianificato svuota l'intera tabella con il periodo configurato. Se l'utente MySQL non ha il privilegio CREATE, la pagina delle impostazioni stampa l'SQL da eseguire a mano e lascia l'opzione disattivata.

La query min/max dello slider del prezzo scansiona postmeta nei negozi grandiMemorizzare min/max per hash SQL per richiesta e in un transient, svuotarlo al salvataggio del prodotto

get_filtered_price() costruisce una sola SELECT MIN/MAX su _price unita alla tax e meta query correnti. Lo stesso intervallo veniva richiesto più volte per pagina (min e max per ogni filtro prezzo), perciò il risultato è memorizzato in un array statico con chiave md5 dell'SQL. Con 'Optimize price filter' attivo, i risultati vanno anche in un unico transient per un giorno, e qualsiasi woocommerce_update_product lo elimina. L'SQL passa per woof_get_filtered_price_query, così un sito può aggiungere index hint.

Gli alberi dei termini vengono ricostruiti da zero per ogni tassonomia a ogni paginaMettere in cache gli alberi assemblati nei transient con chiave argomenti e lingua corrente

WOOF_HELPER::get_terms() carica tutti i termini di una tassonomia con get_categories() e assembla in PHP l'albero genitore-figlio. Il risultato è memorizzato per richiesta e, con 'Cache terms' attivo, salvato in un transient la cui chiave include tassonomia, hide_empty, flag di profondità e la lingua corrente di WPML o Polylang, così ogni lingua ha il proprio albero in cache.

La pulizia scorre wp_options alla ricerca di _transient_woof_terms_cache_% ed elimina ciascun transient, dato che WordPress non ha un'eliminazione per prefisso dei transient.

Il conteggio viene eseguito anche se il visitatore non apre mai il filtroMostrare un pulsante al posto del modulo e caricare il modulo via AJAX al primo clic

Con start_filtering_btn=1 il server emette solo un pulsante, così al caricamento della pagina non girano query sui termini. Al clic, front.js invia woof_draw_products con lo shortcode dei prodotti impostato su 'woof_nothing': il server renderizza il modulo del filtro e nessun prodotto, la zona di ridisegno viene sostituita e i widget vengono reinizializzati. Il pulsante viene saltato quando è già attiva una ricerca, così una pagina filtrata mostra comunque la propria selezione.

Nascondere il modulo con regole CSS o display non fa risparmiare nulla, perché i conteggi sono calcolati sul server prima che l'HTML venga inviato. Nelle discussioni sulle prestazioni sul forum di supporto è spesso stato necessario chiarire questo punto.

Lavorare dentro la query dei prodotti di WooCommerce

nel prodotto

Cosa offreIl filtro continua a funzionare con il tema dello shop, le pagine di categoria, i prodotti variabili, le imposte e le valute, così gli acquirenti non vedono mai articoli in taglie esaurite.

Problema
Il filtro modifica la query principale dello shop e si appoggia a template WooCommerce che non gli appartengono. Deve continuare a funzionare attraverso i cambiamenti del modello dati di WooCommerce, con prodotti variabili, visibilità del catalogo, imposte e plugin per le valute.
Soluzione

Agganciarsi in ritardo a parse_query e alla query dei prodotti di WooCommerce, ripristinare lo stato di archivio che i template si aspettano e gestire esplicitamente ogni differenza del modello dati per versione o per tabella.

Stack
  • WP_Query
  • WooCommerce
  • MySQL
  • jQuery
Attività · 6
I risultati filtrati devono essere renderizzati dal template dello shop del temaRiscrivere i flag della query principale a parse_query con priorità 9999 perché venga renderizzata come archivio prodotti

Quando lo slug di ricerca è nella richiesta, parse_query() imposta post_type=product e is_post_type_archive, e azzera is_tax, is_tag, is_home, is_single e is_search. WooCommerce e il tema renderizzano allora il loop dello shop per qualsiasi URL filtrato. Le estensioni aggiungono le proprie condizioni meta tramite assemble_query_params(), e gli operatori per tassonomia provengono dal filtro woof_main_query_tax_relations.

Gli stessi hook non devono toccare le richieste REST e Store API. I gestori terminano subito sugli URL /wp-json/ e parse_query viene sganciato su rest_api_init, così i temi a blocchi e i client headless ricevono i risultati propri di WooCommerce.

Filtrando in una pagina di categoria si perde la categoriaTrasportare il termine come really_curr_tax e conservarlo in un transient con chiave l'IP del visitatore

Un URL del filtro non è più l'archivio del termine, quindi get_queried_object() smette di restituire la categoria. Quando l'archivio viene renderizzato, set_really_current_term() salva il termine tramite WOOF_STORAGE, che il plugin esegue in modalità transient: un transient per visitatore, con chiave l'hash dell'IP del visitatore, conservato per un giorno. Il JS aggiunge inoltre really_curr_tax=<term_id>-<taxonomy> al link del filtro, e get_really_current_term() ripiega su di esso quando non c'è nulla di salvato. Il termine viene poi messo in AND nella query dei prodotti, nelle query di conteggio e nella ricerca testuale. Le richieste AJAX leggono il termine salvato ma non lo sovrascrivono mai.

La visibilità del catalogo è salvata in modo diverso a seconda della versione di WooCommerceRamificare per versione: meta _visibility prima della 3.0, product_visibility NOT IN dopo

WooCommerce 3.0 ha spostato i flag di visibilità, in evidenza ed esaurito da postmeta alla tassonomia product_visibility. product_visibility_not_in() trasforma i flag necessari in clausole term_taxonomy_id NOT IN. generate_visibility_keys() aggiunge outofstock quando il negozio nasconde gli articoli esauriti; quando l'opzione 'listen catalog visibility' è attiva, aggiunge anche sempre exclude-from-search ed exclude-from-catalog fuori da una ricerca. I negozi più vecchi ricevono invece una condizione meta _visibility.

Le stesse regole sono applicate alla query principale, alla query dello shortcode, alle query di conteggio, alla ricerca testuale e ai dati della modalità turbo. Se una di esse differisce, conteggi e risultati non coincidono.

Prodotto variabile mostrato mentre la taglia scelta è esauritaTrovare nella tabella di lookup degli attributi i genitori delle varianti corrispondenti esaurite, escluderli

Un prodotto variabile conta come disponibile se lo è una qualsiasi delle sue varianti, perciò una query semplice per 'disponibile + taglia M' restituisce una camicia la cui variante M è esaurita. Quando il filtro di disponibilità è combinato con filtri di attributo, posts_where() raccoglie i termini pa_* selezionati, incluso il termine contato durante il conteggio, ed esegue due query raggruppate su wc_product_attributes_lookup: i genitori con una variante corrispondente esaurita e i genitori con una variante corrispondente disponibile. La differenza viene aggiunta come ID NOT IN.

Una modalità più vecchia, selezionabile nelle impostazioni del filtro di disponibilità, interroga invece i post product_variation per meta dell'attributo e _stock_status, al posto della tabella di lookup. È più lenta, e per impostazione predefinita esclude ogni genitore che ha una variante corrispondente esaurita; i genitori che hanno anche una corrispondenza disponibile vengono mantenuti solo quando il filtro woof_exclude_existing_variations restituisce true.

I limiti di prezzo differiscono dai prezzi salvati con imposte e valuteRiconvertire i limiti nella valuta base e togliere l'imposta inclusa prima della meta query

_price è salvato nella valuta base dello shop e, in molti negozi, senza imposte. Se il visitatore usa una valuta WPML (WCML), assemble_price_params() riconverte i limiti nella valuta base. Se i prezzi sono mostrati con imposte ma salvati senza, l'imposta inclusa per l'aliquota standard viene sottratta da entrambi i limiti. Per l'estremo superiore dello slider, get_max_price() trova il prodotto che ha il prezzo massimo e chiede a WooCommerce il suo prezzo comprensivo di imposte.

Con FOX (WOOCS) i valori mostrati dello slider sono convertiti tramite woocs_exchange_value mentre la query mantiene numeri nella valuta base.

Modalità AJAX: ridisegnare risultati, conteggi e parti della pagina senza ricaricarlaUn solo endpoint AJAX renderizza prodotti e modulo tramite shortcode; il JS sostituisce le zone e aggiorna l'URL

woof_draw_products() ricostruisce $_GET dal link che il visitatore avrebbe aperto, renderizza [woof_products] e [woof] con quello stato e restituisce in JSON prodotti, modulo e frammenti aggiuntivi (numero di risultati, ordinamento, paginazione). front.js sostituisce ogni frammento, rimette quelli che la risposta non includeva, reinizializza i widget e chiama history.pushState così che l'URL possa essere condiviso. onpopstate ricarica la pagina quando la query string è cambiata. Un flag di blocco scarta i clic mentre una richiesta è in corso.

Il loop dello shop è racchiuso agganciandosi a woocommerce_before_shop_loop e woocommerce_after_shop_loop. I temi che non attivano entrambi gli hook rompono la modalità AJAX, il che spiega un'intera famiglia di discussioni di supporto con sintomi diversi e una sola causa.

Modalità turbo: filtrare nel browser

nel prodotto

Cosa offreNei cataloghi grandi il filtraggio gira nel browser dell'acquirente invece che sul server. I risultati compaiono rapidamente e il server ha meno carico nelle ore di punta.

Problema
Nei cataloghi grandi ogni clic sul filtro costa sul server un insieme di join su tassonomie e meta, più una query di conteggio per ogni termine visibile.
Soluzione

Precalcolare un indice JSON piatto di prodotti e varianti, caricarlo nel browser ed eseguire il filtro come SQL su di esso con AlaSQL. Il server renderizza solo gli ID corrispondenti. Inclusa in entrambe le edizioni.

Stack
  • PHP
  • JSON
  • AlaSQL
  • JavaScript
  • Cron
Attività · 5
I dati del prodotto sono distribuiti tra post, postmeta, termini e variantiAppiattire ogni prodotto e variante in un unico record JSON: prezzi, termini, meta, disponibilità

get_data_by_id() scrive ID, titolo, SKU, autore, genitore, stato di disponibilità, gli slug dei termini di ogni tassonomia filtrabile (attributi della variante per le varianti), i campi meta configurati e un elenco di coppie di prezzo regolare/in offerta. Un prodotto variabile salva una coppia per ogni figlio, così il browser può calcolarne l'intervallo di prezzo con la stessa regola usata da WooCommerce: il prezzo in offerta conta solo quando è inferiore al prezzo regolare.

I prezzi sono salvati con le imposte quando lo shop mostra prezzi comprensivi di imposte, e FOX viene portato sulla valuta predefinita prima di leggerli, così l'indice è in un'unica valuta.

Indicizzare migliaia di prodotti raggiunge i limiti di tempo di PHPCostruire a passi AJAX da 10 prodotti, un file per lingua WPML e per blog multisite

create_data_search_files() riceve un offset, elabora 10 ID di prodotti e varianti applicando le regole di visibilità, li unisce nel file JSON e restituisce l'offset successivo; lo script di amministrazione cicla finché non riceve -1. WPML viene portato sulla lingua predefinita e ogni prodotto viene scritto nel file di ogni lingua tramite il suo ID di traduzione. check_id_file() aggiunge l'ID del blog nel multisite, così i siti non condividono un file.

Il limite predefinito è 15,000 record, regolabile con il filtro woof_turbo_mode_products_limit.

Una ricostruzione pianificata non deve servire un indice scritto a metàUn proprio cron runner elabora porzioni di ID per richiesta e a fine lavoro scambia un file _temp

PN_WP_CRON_WOOF_TURBO_MODE conserva lo stato dell'evento (elenco completo degli ID, posizione, prossima esecuzione) in un'opzione ed è eseguito su init. Ogni chiamata a process() gestisce una porzione di 10 ID, e un limite di 5 secondi salvato in woof_cron_limit_do impedisce a una raffica di visualizzazioni di pagina di eseguire le porzioni una dopo l'altra. Le porzioni sono scritte in data_<id>_temp_<lang>.json; quando l'elenco è esaurito, do_recreate_file() sposta il file temporaneo sopra quello attivo, e i visitatori mantengono il vecchio indice finché il nuovo non è completo.

Il costo di questa progettazione è l'obsolescenza: i prodotti aggiunti dopo l'ultima ricostruzione sono invisibili al filtro, e la ricostruzione dipende dal traffico del sito allo stesso modo di WP-Cron.

Lo stato del filtro deve diventare una query che il browser possa eseguireGenerare clausole WHERE di AlaSQL con funzioni personalizzate per intervalli di prezzo e visibilità

turbo_mode.js trasforma i valori correnti in una stringa WHERE: appartenenza alle tassonomie tramite indexOf sugli array dei termini, confronti meta, LIKE per SKU e titolo, BETWEEN per slider e date. Funzioni AlaSQL personalizzate calcolano il prezzo minimo e massimo di un prodotto dall'elenco delle sue varianti e applicano la visibilità del catalogo. Per i prodotti variabili il filtro di disponibilità seleziona prima i genitori delle varianti esaurite che corrispondono agli altri filtri. Il conteggio gira sulla stessa tabella in memoria.

Gli ID risultanti vengono inviati a woof_draw_products come turbo_mode_ids, e il server renderizza una query post__in al posto dei join del filtro.

Il browser ha bisogno delle impostazioni, ma queste contengono segreti del serverRimuovere dalle impostazioni localizzate le credenziali del DB delle statistiche e le chiavi segrete del cron

Il JS ricostruisce la logica del filtro da woof_settings, quindi ha bisogno sulla pagina della maggior parte di quell'opzione. get_public_settings() rimuove il blocco delle statistiche, che contiene le credenziali del MySQL esterno, e ogni cron_secret_key, e passa il resto attraverso un filtro per ulteriori rimozioni. Nella versione premium l'endpoint di ricostruzione richiede un nonce e manage_woocommerce.

Statistiche di ricerca

nel prodotto

Cosa offreIl proprietario vede per cosa gli acquirenti filtrano e cercano davvero, senza rallentare lo shop né riempire il suo database con un log in continua crescita.

Problema
Registrare i criteri con cui gli acquirenti filtrano significa scrivere sul percorso critico di ogni visualizzazione di pagina filtrata, da parte di visitatori anonimi e bot, spesso su hosting condiviso.
Soluzione

Scrivere una piccola riga grezza per richiesta in una tabella di appoggio, e tenere le statistiche a lungo termine su un server MySQL separato richiesto dall'estensione.

Stack
  • MySQL
  • PDO
Attività · 2
La registrazione non deve moltiplicare le scritture né essere sommersa da un solo clientRegistrare una volta per richiesta, deduplicare con un hash richiesta+IP+giorno, limitare le righe di appoggio per IP

L'estensione delle statistiche si aggancia a woof_get_request_data, che viene eseguito molte volte per pagina; un flag statico limita la registrazione alla prima chiamata, e le chiamate AJAX diverse dal rendering dei prodotti vengono ignorate. Vengono conservate solo le chiavi del filtro scelte nelle impostazioni, la richiesta viene tagliata a request_max_deep chiavi (5 per impostazione predefinita) preservando l'intervallo di prezzo, e ne viene calcolato l'hash insieme a IP e data.

Una riga viene inserita solo se quell'hash è nuovo e l'IP ha meno di user_max_requests righe (10 per impostazione predefinita) nella tabella di appoggio.

Le statistiche crescono senza limiti dentro il database dello shopSalvare le statistiche su un server MySQL separato tramite PDO, una tabella per mese

L'estensione richiede un proprio server MySQL, indicato nelle opzioni. init_pdo() vi si connette con PDO, dato che $wpdb non può gestire una seconda connessione con altre credenziali. place_statdata_into_db() crea una tabella per mese chiamata <year>_<month> e inserisce le righe con prepared statement.

I report interrogano le tabelle mensili per intervallo di date, così il database dello shop non conserva le statistiche a lungo termine.

Hardening e integrità delle impostazioni

nel prodotto

Cosa offreI visitatori anonimi non possono usare il filtro per eseguire codice o raggiungere dati nascosti, e le impostazioni salvate non vanno perse né sovrascritte quando si fanno modifiche.

Problema
Il filtro riceve query string e invii AJAX da visitatori anonimi, renderizza shortcode e template indicati in quelle richieste, e salva impostazioni che contengono HTML, JavaScript e SQL. Il changelog attribuisce a ricercatori esterni una serie di segnalazioni di sicurezza dal 2022 al 2026.
Soluzione

Trattare ogni valore della richiesta come dato: consentire solo shortcode e template noti, sanificare ricorsivamente le impostazioni per percorso di chiave, richiedere capability per tutto ciò che salva codice e unire le impostazioni invece di sovrascriverle.

Stack
  • PHP
  • WordPress sanitization API
  • WPML
  • Polylang
Attività · 5
Le richieste AJAX trasportano il nome di un template PHP da renderizzareAccettare solo nomi di template visti per la prima volta nel contenuto della pagina; l'AJAX non può aggiungerne di nuovi

[woof_products custom_tpl=...] viene legittimamente rinviato nelle chiamate AJAX, quindi il valore non può né essere considerato attendibile né scartato. sanitize_custom_tpl() conserva solo lettere, cifre, '_', '-' e '/', il che rimuove punti e sequenze di traversal. Un nome renderizzato da contenuto reale della pagina viene aggiunto a un'opzione allowlist (si conservano gli ultimi 20); durante l'AJAX sono accettati solo i nomi già presenti in quell'elenco.

I percorsi di include costruiti dai nomi dei tipi di vista passano per safe_view_slug(), che rifiuta tutto ciò che non è un semplice slug.

Le richieste AJAX trasportano testo di shortcode che non deve eseguire shortcode arbitrariEstrarre dal testo inviato solo i tag propri del plugin con get_shortcode_regex

woof_draw_products() riceve dalla pagina il testo degli shortcode dei prodotti e del modulo, così l'output AJAX corrisponde alla chiamata originale. check_shortcode() costruisce get_shortcode_regex() solo per i tag del plugin ([woof_products] o [woof], più gli alias dello shortcode prodotti del plugin) e mantiene la prima corrispondenza; tutto il resto della stringa viene scartato prima di do_shortcode().

Le impostazioni mescolano HTML, JavaScript, slug e testo semplice a qualsiasi profonditàSanificare ricorsivamente; classificare ogni campo per la sua chiave o per il suo percorso nell'albero delle impostazioni

sanitize_array() percorre l'albero delle impostazioni, salva ogni valore sotto la sua chiave sanificata e classifica ogni campo per nome o per percorso nell'albero: il testo delle regole SEO come HTML tramite wp_kses_post, le descrizioni come textarea, le chiavi usate nei percorsi di include come slug rigorosi, tutto il resto come testo semplice. Servono regole per percorso perché le chiavi in profondità nell'albero, come text o description, sono troppo generiche per essere elencate globalmente.

L'impostazione 'JavaScript after AJAX' può essere modificata solo dagli utenti con unfiltered_html.

La risposta AJAX inietta frammenti HTML, e la richiesta è ricostruita dall'URL del visitatoreEliminare woof_redraw_elements dal link analizzato (premium); far passare ogni frammento per wp_kses

Il rendering AJAX ricostruisce $_GET dal link di pagina inviato dal browser, e la risposta inietta woof_redraw_elements nella pagina come HTML, quindi un link costruito ad arte non deve poter fornire quella chiave. Nella versione premium la chiave viene rimossa dal link analizzato. I frammenti legittimi (titolo SEO e H1, numero di risultati, ordinamento) sono aggiunti da filtri lato server, e ogni frammento passa per wp_kses prima di essere restituito.

Colori e immagini dei termini dovrebbero essere impostati una volta per tutte le lingueUnire i colori per termine inviati a quelli salvati; ripiegare sul termine della lingua predefinita

La pagina delle impostazioni elenca solo i termini della lingua corrente di WPML o Polylang, quindi un salvataggio invia i colori solo per quei termini. woof_save_options() unisce le voci color, color_img e images_term_* già salvate sotto i valori inviati, così le altre lingue mantengono i propri.

Un termine tradotto senza un colore proprio usa il suo originale nella lingua predefinita, trovato da get_original_language_term(). Legge lo slug direttamente da wp_terms, perché con l'adeguamento degli ID di WPML get_term() può restituire di nuovo il termine tradotto.

Debugging sul campo

support forum

Cosa offreI problemi in uno shop in produzione vengono trovati alla loro vera causa, anche quando è il tema, il server, una cache o un altro plugin.

Problema
La segnalazione da uno shop in produzione indica un sintomo, non una causa. Lo stesso sintomo può venire da un template del tema, da un livello di cache o di ottimizzazione, dal server, da un altro plugin o dal filtro stesso.
Soluzione

Riprodurre su un'installazione pulita o su una copia del sito, escludere un livello alla volta e correggere dove sta la causa: nel plugin per tutti, oppure con una modifica mirata su quel sito.

Stack
  • Browser DevTools
  • Nginx
  • LiteSpeed Cache
  • jQuery
  • ACF
  • MySQL
Attività · 5
I toggle delle sottocategorie scompaiono e il filtro non funziona ogni volta che l'URL ha una query stringIl guasto è stato isolato sul server con un test con un parametro GET arbitrario, poi è stata corretta la rewrite di Nginx

Anche un parametro privo di senso come ?dwdadd=1adw rompeva la pagina, il che dimostrava che il guasto era nella gestione della query string, non nel filtro. La configurazione di Nginx inseriva un ? di troppo dopo php ed eliminava ogni parametro, quindi il filtro non riceveva mai i propri argomenti.

Lo shop smette di aggiornarsi dopo il filtraggio una volta installato LiteSpeed CacheRegistrata la risposta AJAX per evidenziare un errore di parsing JSON, poi isolate per bisezione le impostazioni di LiteSpeed fino a CDN Mapping

La risposta arrivava ma JSON.parse falliva per un carattere di escape errato, il che significava che il CDN Mapping di LiteSpeed riscriveva gli URL al suo interno. Disattivare CDN Mapping ha ripristinato il filtraggio.

I pulsanti Filter e Reset aggiornano l'URL ma l'elenco dei prodotti non si ricarica maiRicondotto alla build slim di jQuery, ripristinato jQuery completo e sostituito il core WordPress modificato dall'host con un'installazione pulita

Il sito caricava jQuery slim, che non ha il modulo AJAX, quindi la richiesta dei risultati filtrati non veniva mai inviata mentre l'URL cambiava comunque lato client; disattivare tutti gli altri plugin non cambiava nulla. La build slim veniva da un core WordPress modificato dall'auto-installer dell'host; ripristinare jQuery completo e reinstallare il core ha risolto il problema.

Gli slider meta su piccoli valori decimali ACF (intorno a .005) non filtrano nulla o filtrano tuttoAggiunto il filtro woof_slider_meta_query_type così il cast SQL può essere impostato su DECIMAL per chiave meta

Chi aveva segnalato il problema ha ricostruito il campo come semplice campo personalizzato e il difetto è rimasto, quindi ACF non era la causa; il supporto lo ha riprodotto. La meta query confrontava i valori senza un cast DECIMAL, e il plugin ha ottenuto l'hook woof_slider_meta_query_type, che riceve $type e $key.

Il filtro si blocca dopo il pulsante Indietro del browser; Search non fa nullaAggiunto un listener pageshow che azzera il blocco dell'invio e il popup al ripristino dalla bfcache, rilasciato con gli aggiornamenti

Le pagine ripristinate dalla cache avanti/indietro mantenevano woof_submit_link_locked impostato e il popup di caricamento aperto. Il listener controlla event.persisted o il tipo di navigazione 2 e azzera entrambi; la modifica è entrata nel plugin.

Numeri

wordpress.org
  • Installazioni attive 80.000+ contatore di wordpress.org.
  • Recensioni 336 Media 4.6 su 5.
  • Anni di supporto 12 Dal 1 dicembre 2014, ultimo aggiornamento 9 ottobre 2026.