HUSKY aka WOOF
Permette ai clienti di restringere un catalogo ampio per categoria, attributo, prezzo, disponibilità e testo, con pagine di filtro che Google può indicizzare.
Porto un prodotto dalla prima specifica fino alla coda di supporto anni dopo. 12 plugin su wordpress.org, un SaaS che trasforma un negozio WooCommerce in un bot Telegram, un'estensione per Chrome e app 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;
Progetti
Ogni pagina di progetto elenca i problemi risolti all'interno del prodotto, raggruppati per area. Il numero di installazioni e le valutazioni provengono da wordpress.org, dove si può leggere ciò che scrivono gli utenti: HUSKY recensioni, FOX recensioni, BEAR recensioni.
Permette ai clienti di restringere un catalogo ampio per categoria, attributo, prezzo, disponibilità e testo, con pagine di filtro che Google può indicizzare.
Mostra i prezzi nella valuta del visitatore e può accettare il pagamento in essa, così i clienti stranieri sanno cosa pagano.
Permette al personale di modificare migliaia di prodotti come in un foglio di calcolo, con ogni modifica annullabile, e consente agli assistenti IA di farlo in sicurezza.
Mostra il catalogo come tabelle di prodotti ordinabili e filtrabili, in cui i clienti aggiungono articoli al carrello direttamente da ogni riga.
Permette al personale del sito di modificare, filtrare, esportare e ripristinare migliaia di articoli, pagine e contenuti personalizzati in un'unica schermata simile a un foglio di calcolo.
I visitatori cercano annunci, articoli o prodotti per più proprietà contemporaneamente, come prezzo, anno e categoria.
Mostra i prezzi scritti nei contenuti del sito nella valuta di ciascun visitatore, senza bisogno di un negozio WooCommerce.
Mostra articoli o prodotti come tabelle ordinabili e ricercabili che i visitatori possono filtrare e sfogliare su qualsiasi dispositivo.
Si allega un insieme di immagini a qualsiasi articolo e lo si mostra come galleria o slider in qualsiasi punto del sito.
Menu a discesa passo dopo passo, come marca, modello e generazione, guidano i visitatori in un catalogo ampio fino alla pagina o al prodotto giusto.
Un negozio WooCommerce gestito come bot Telegram: i clienti sfogliavano, riempivano il carrello e pagavano senza uscire dalla chat.
Un'estensione per Chrome che scrive ciò che si dice in qualsiasi campo di testo di qualsiasi sito, con revisione facoltativa tramite IA.
Un cronometro Android offline con tempi sul giro che continua a contare correttamente anche quando l'app è in background.
Un lettore che mostra un testo una parola alla volta al ritmo scelto e ricorda dove ci si è fermati.
Aziende come bolle su un grafico a quadranti che si spostano al variare dei pesi del modello.
Raccolta di eventi, aggregazione e report con grafici nell'area di amministrazione di WordPress.
Un cliente si iscrive a una query di filtro e riceve un'e-mail quando compaiono nuovi prodotti corrispondenti.
Un PDF ben impaginato con tutte le auto dell'insieme di risultati corrente di un catalogo di veicoli.
Cosa è stato risolto · 14 prodotti
Scelga un prodotto. Ogni scheda è un'area del suo lavoro e inizia con ciò che offre al proprietario, in parole semplici. Sotto c'è la parte ingegneristica per i Suoi tecnici: il problema e come è stato risolto, ricavato dal codice sorgente. Apra una riga per i dettagli.
cosa è stato risolto · scegli un progetto
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.
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à.
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().
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
_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.
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.
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
Cosa offreGli acquirenti trovano i prodotti per SKU, attributo o parole nelle descrizioni delle varianti. I clienti registrati possono salvare una ricerca e ricevere una notifica quando arrivano nuovi prodotti corrispondenti.
Costruire la clausola WHERE da frammenti preparati per singola parola, con join aggiunti solo quando servono, risolvere le varianti nei genitori in una query separata, limitare ciò che l'endpoint pubblico può richiedere e rieseguire le ricerche salvate da SQL catturato dal server.
create_where_query() divide la frase in parole. Per ogni parola mette in OR i campi del post selezionati e le chiavi meta elencate (lo SKU è semplicemente _sku), più una corrispondenza del nome del termine sull'intera frase, e i gruppi di parole sono messi in AND. Un '-' iniziale trasforma una parola in NOT LIKE unito con AND. I frammenti passano per $wpdb->prepare().
I join con termini e postmeta vengono aggiunti in posts_join solo quando quelle opzioni sono attive, e posts_groupby elimina le righe duplicate create dai join.
Le varianti sono post separati, e la query del genitore non vede _variation_description. Quando l'opzione è attiva, una query trova i post product_variation la cui descrizione contiene tutte le parole, una seconda li mappa su post_parent, e la clausola principale diventa (condizioni sulle parole OR ID IN (genitori)). L'elenco dei genitori può essere messo nell'object cache per elenco di parole.
ajax_search() è aperta agli ospiti e pagina la query in SQL usando max_posts come dimensione della pagina, così viene caricata solo una pagina di corrispondenze. Nella versione premium, max_posts dalla richiesta è limitato tra 1 e il maggiore tra l'impostazione di amministrazione e un 100 filtrabile. I suggerimenti rispettano lo stato corrente del filtro, la pagina di categoria e la restrizione ai prodotti in offerta.
Il filtro testuale costruisce la propria query di ricerca, quindi un plugin di ricerca separato non può decidere l'insieme dei risultati nella stessa richiesta; le discussioni di supporto elencano Ivory Search, Relevanssi e Advanced Woo Search tra questi conflitti. get_all_ids() applica per prima cosa il filtro woof_text_search_ids. Quando una callback restituisce un array, per esempio gli ID da SearchWP, quell'array è l'insieme delle corrispondenze e l'SQL integrato viene saltato. Collegare un dato motore richiede codice personalizzato.
La vista Products Messenger salva $wp_query->request, l'SQL generato da WordPress per i risultati filtrati, nell'archivio per visitatore del plugin sotto l'ID utente. Alla sottoscrizione, che richiede un utente autenticato, il server lo rilegge da quell'archivio e non dalla richiesta, rimuove LIMIT, verifica che sia una singola SELECT senza parole chiave DML o DDL, la esegue una volta per registrare una base di ID e salva la sottoscrizione nei user meta.
Il job pianificato riesegue ogni query salvata e invia per e-mail solo gli ID che non sono nella base, poi estende la base. Una sottoscrizione termina per numero di messaggi o per data. I user meta vengono aggiornati solo quando wp_mail() ha successo, così un invio fallito viene ritentato all'esecuzione successiva.
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.
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.
[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.
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().
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.
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.
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.
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.
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.
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.
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.
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.
woof_slider_meta_query_type così il cast SQL può essere impostato su DECIMAL per chiave metaChi 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.
pageshow che azzera il blocco dell'invio e il popup al ripristino dalla bfcache, rilasciato con gli aggiornamentiLe 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.
Anello interno: stack principale · anello esterno: strumenti e piattaforme
Chi sono · stack
Progetto l'architettura e il modello dei dati, poi scrivo il codice, lo rilascio e lo supporto. Nessun livello viene affidato a qualcuno che non posso verificare.
Sviluppo su misura
Lavori su misura per i clienti, di solito persone che hanno iniziato con uno dei miei plugin. Nomi e siti restano riservati.
Una grande directory B2B di fornitori costruita su WordPress.
Lo stesso portale WordPress.
Nato come lavoro su misura per il titolare di un negozio, poi rilasciato come estensione Products Messenger per HUSKY e MDTF.
Un catalogo di veicoli costruito su MDTF, add-on personalizzato per un cliente in Germania.
Integrato, non aggiunto dopo
I proprietari ottengono i numeri nella stessa area di amministrazione in cui configurano il plugin.
Cronologia
Solo i miei prodotti. Le date di rilascio sono le date in cui ciascun plugin è stato aggiunto a wordpress.org.
Prima di scrivere
Descriva l'incarico nel modulo qui sotto o via e-mail a realmag777 [at] gmail.com: cosa va creato o modificato e per quando. Se dispone di un sito di staging, lo indichi: è lì che il lavoro viene svolto e verificato. Rispondo entro due giorni lavorativi con domande o con una stima di tempi e costi. Il lavoro inizia una volta concordato l'ambito.
Un incarico descritto con chiarezza riceve una stima fissa per l'ambito concordato. Il lavoro aperto, come trovare la causa di un problema su un sito in produzione o il supporto continuativo, si concorda a ore.
Ora dell'Europa centrale (UTC+1, UTC+2 in estate). Scrivo e parlo in Inglese, ucraino e spagnolo. Gran parte del lavoro avviene via e-mail e messaggi, quindi la differenza di fuso raramente conta.
Sì. I nomi dei clienti e i loro siti non vengono mai mostrati qui, e firmo un NDA quando il progetto lo richiede.
No. Realizzo funzionalità aggiuntive ai miei plugin o a qualsiasi altro, lavoro su codice scritto da altri sviluppatori e progetto nuovi progetti da zero. Con il codice di qualcun altro lo leggo prima e Le dico cosa ho trovato prima di cambiare qualsiasi cosa.
Da solo. Architettura, codice, rilascio e supporto sono miei, quindi si parla con la persona che costruisce il prodotto e nulla si perde tra le persone.
Sì, anche con il marchio dell'agenzia. Scriva chi è e di cosa ha bisogno.
Per accordo. Mi parli del progetto e del volume che prevede, e lo definiamo prima dell'inizio del lavoro.
In euro.
Un sito di staging, una copia di quello in produzione, con accesso all'amministrazione e ai file, più una copia del database quando l'incarico riguarda i dati. Se non c'è un sito di staging, lo configuro io. Le modifiche arrivano sul sito in produzione solo dopo aver funzionato in staging.
Suo, una volta pagato il lavoro.
Gli errori nel lavoro consegnato vengono corretti. Ulteriori modifiche e supporto si possono concordare separatamente. I miei plugin sono supportati da oltre dieci anni, quindi la manutenzione a lungo termine è la norma, non l'eccezione.
Contatti
Scriva cosa va creato o modificato e per quando. Rispondo entro due giorni lavorativi.
realmag777 [at] gmail.com linkedin.com/in/realmag777