Merged in release/release-1.09 (pull request #10)

Release/release 1.09

* Install missing plugins 
* rs set to 1

* rebase pantheon for aws

* rebase pantheon for aws

* prod config change

* prod config change

* fix campaing issue

* revert


Approved-by: Jay Sharma
This commit is contained in:
Rachit Bhargava
2023-12-27 20:55:58 +00:00
committed by Jay Sharma
parent 779393381f
commit 22f10a9edd
2154 changed files with 22313 additions and 209875 deletions

View File

@@ -1 +0,0 @@
<?php return array('dependencies' => array('wp-components', 'wp-compose', 'wp-data', 'wp-edit-post', 'wp-element', 'wp-i18n', 'wp-plugins', 'wp-polyfill'), 'version' => '3cf891ee5aaa21141e30e23ad95d485e');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,99 +0,0 @@
{
"translation-revision-date": "",
"generator": "WP-CLI\/2.4.0",
"source": "src\/index.js",
"domain": "messages",
"locale_data": {
"messages": {
"": {
"domain": "messages",
"lang": "fi",
"plural-forms": "nplurals=2; plural=(n != 1);"
},
"not this": [
"ei t\u00e4t\u00e4"
],
"use this": [
"k\u00e4yt\u00e4 t\u00e4t\u00e4"
],
"How Relevanssi sees this post": [
"Kuinka Relevanssi n\u00e4kee artikkelin"
],
"Title:": [
"Otsikko:"
],
"Content:": [
"Sis\u00e4lt\u00f6:"
],
"Author:": [
"Tekij\u00e4:"
],
"Categories:": [
"Aiheet:"
],
"Tags:": [
"Avainsanat:"
],
"Other taxonomies:": [
"Muut taksonomiat:"
],
"Comments:": [
"Kommentit:"
],
"Custom fields:": [
"Avainkent\u00e4t:"
],
"Excerpt:": [
"Ote:"
],
"Links to this post:": [
"Sis\u00e4iset linkit:"
],
"MySQL columns:": [
"MySQL-sarakkeet:"
],
"Reason this post is not indexed:": [
"Miksi t\u00e4t\u00e4 artikkelia ei ole indeksoitu:"
],
"Pinning": [
"Artikkelin kiinnitt\u00e4minen"
],
"Pin this post for all searches it appears in.": [
"Kiinnit\u00e4 t\u00e4m\u00e4 artikkeli k\u00e4rkeen kaikissa hauissa, joissa se esiintyy."
],
"A comma-separated list of single word keywords or multi-word phrases. If any of these keywords are present in the search query, this post will be moved on top of the search results.": [
"Pilkuilla erotettu lista yksitt\u00e4isi\u00e4 hakusanoja tai monisanaisia hakulauseita. Jos joku n\u00e4ist\u00e4 hakusanoista esiintyy k\u00e4ytt\u00e4j\u00e4n haussa, t\u00e4m\u00e4 artikkeli kiinnitet\u00e4\u00e4n hakutulosten huipulle."
],
"Exclusion": [
"Artikkelien poissulkeminen"
],
"Exclude this post or page from the index.": [
"Poista t\u00e4m\u00e4 artikkeli indeksist\u00e4."
],
"A comma-separated list of single word keywords or multi-word phrases. If any of these keywords are present in the search query, this post will be removed from the search results.": [
"Pilkuilla erotettu lista yksitt\u00e4isi\u00e4 hakusanoja tai monisanaisia hakulauseita. Jos joku n\u00e4ist\u00e4 hakusanoista esiintyy k\u00e4ytt\u00e4j\u00e4n haussa, t\u00e4m\u00e4 artikkeli poistetaan hakutuloksista."
],
"Related posts": [
"Aiheeseen liittyv\u00e4t artikkelit"
],
"Don't append the related posts to this page.": [
"\u00c4l\u00e4 lis\u00e4\u00e4 samankaltaisia artikkeleita t\u00e4lle sivulle."
],
"Don't show this as a related post for any post.": [
"\u00c4l\u00e4 n\u00e4yt\u00e4 t\u00e4t\u00e4 samankaltaisena artikkelina mill\u00e4\u00e4n sivulla."
],
"A comma-separated list of keywords to use for the Related Posts feature. Anything entered here will used when searching for related posts. Using phrases with quotes is allowed, but will restrict the related posts to posts including that phrase.": [
"Pilkulla erotettu lista avainsanoja samankaltaisten artikkelien etsimiseen. T\u00e4h\u00e4n merkittyj\u00e4 hakusanoja k\u00e4ytet\u00e4\u00e4n samankaltaisten artikkelien etsimiseen. Voit k\u00e4ytt\u00e4\u00e4 fraasihakua lainausmerkeill\u00e4, mutta se rajoittaa samankaltaiset artikkelit niihin, joissa fraasi esiintyy."
],
"A comma-separated list of post IDs to use as related posts for this post": [
"Pilkuilla erotettu lista t\u00e4m\u00e4n artikkelin liittyvin\u00e4 artikkeleina k\u00e4ytett\u00e4vien artikkelien ID-numeroista"
],
"Related posts for this post:": [
"Samankaltaiset artikkelit:"
],
"Excluded posts for this post:": [
"\u00c4l\u00e4 k\u00e4yt\u00e4 samankaltaisina artikkeleina t\u00e4lle artikkelille:"
]
}
}
}

View File

@@ -1,321 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: Relevanssi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-14 14:06+0200\n"
"PO-Revision-Date: \n"
"Last-Translator: Alessandro Fiorotto <alex@fiorotto.com>\n"
"Language-Team: Fiorotto <alex@fiorotto.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Italian\n"
"X-Poedit-Country: ITALY\n"
"X-Poedit-SourceCharset: utf-8\n"
#: relevanssi.php:703
msgid "There is no excerpt because this is a protected post."
msgstr "Non c'è alcun estratto perché il post è protetto."
#: relevanssi.php:994
msgid "Indexing complete!"
msgstr "Indicizzazione completata!"
#: relevanssi.php:1183
msgid "Relevanssi Search Options"
msgstr "Opzioni per Relevanssi Search"
#: relevanssi.php:1294
#, php-format
msgid "<div id='message' class='update fade'><p>Term '%s' added to stopwords!</p></div>"
msgstr "<div id='message' class='update fade'><p>Termine '%s' aggiunto alle parole inutili ai fini della ricerca!</p></div>"
#: relevanssi.php:1297
#, php-format
msgid "<div id='message' class='update fade'><p>Couldn't add term '%s' to stopwords!</p></div>"
msgstr "<div id='message' class='update fade'><p>Non posso aggiungere il termine '%s' alle parole inutili ai fini della ricerca!</p></div>"
#: relevanssi.php:1306
msgid "25 most common words in the index"
msgstr "Le 25 parole più comuni nell'indice"
#: relevanssi.php:1308
msgid "These words are excellent stopword material. A word that appears in most of the posts in the database is quite pointless when searching. This is also an easy way to create a completely new stopword list, if one isn't available in your language. Click the icon after the word to add the word to the stopword list. The word will also be removed from the index, so rebuilding the index is not necessary."
msgstr "Queste parole possono dimostrarsi inutili ai fini della ricerca. Una parola che compare nella maggior parte dei posti nel database è piuttosto inutile ai fini di una buona ricerca. Questo è anche un modo semplice per creare un nuovo elenco di parole non significative, se non è disponibile nella tua lingua. Fare clic sull'icona dopo la parola per aggiungere la parola alla lista delle parole non significative. La parola sarà rimossa dall'indice e non sarà necessario ricostruire l'indice se si effettua una modifica."
#: relevanssi.php:1331
msgid "Add to stopwords"
msgstr "Aggiungi alle parole inutili ai fini della ricerca"
#: relevanssi.php:1344
msgid "25 most popular queries"
msgstr "25 ricerche più effettuate"
#: relevanssi.php:1356
msgid "Recent queries that got 0 hits"
msgstr "Recenti ricerche che non hanno dato risultati"
#: relevanssi.php:1491
msgid "Title boost:"
msgstr "Potenziamento dal titolo:"
#: relevanssi.php:1492
#, php-format
msgid "Default: %d. 0 means titles are ignored, 1 means no boost, more than 1 gives extra value."
msgstr "Predefinito %d. 0 significa che i titoli sono ignorati, 1 significa non aumentare, mentre più di 1 da un valore in più."
#: relevanssi.php:1493
msgid "Tag boost:"
msgstr "Potenziamento da TAG"
#: relevanssi.php:1494
#, php-format
msgid "Default: %d. 0 means tags are ignored, 1 means no boost, more than 1 gives extra value."
msgstr "Predefinito %d. 0 significa che i tag sono ignorati, 1 significa non aumentare, mentre più di 1 da un valore in più."
#: relevanssi.php:1495
msgid "Comment boost:"
msgstr "Potenziamento dai commenti:"
#: relevanssi.php:1496
#, php-format
msgid "Default: %d. 0 means comments are ignored, 1 means no boost, more than 1 gives extra value."
msgstr "Predefinito %d. 0 significa che i commenti sono ignorati, 1 significa non aumentare, mentre più di 1 da un valore in più."
#: relevanssi.php:1497
msgid "Use search for admin:"
msgstr "Usa ricerca per admin:"
#: relevanssi.php:1498
msgid "If checked, Relevanssi will be used for searches in the admin interface"
msgstr "Se selezionato, Relevanssi sarà usato anche per le ricerche nell'interfaccia di amministrazione"
#: relevanssi.php:1499
msgid "Restrict search to these categories and tags:"
msgstr "Circoscrivi la ricerca a queste categorie e tag:"
#: relevanssi.php:1500
msgid "Enter a comma-separated list of category and tag IDs to restrict search to those categories or tags. You can also use <code>&lt;input type='hidden' name='cat' value='list of cats and tags' /&gt;</code> in your search form. The input field will overrun this setting."
msgstr "Inserire un elenco separato da virgola, con gli id degli articoli e/o delle pagine a cui sarà circoscritto l'ambito di ricerca. Si può anche usare il codice <code>&lt;input type='hidden' name='cat' value='list of cats and tags' /&gt;</code> nel modulo di ricerca e quello che si inserirà nel modulo sovrascriverà quanto impostato qui."
#: relevanssi.php:1501
msgid "Exclude these categories and tags from search:"
msgstr "Escludi queste categorie e tag dalla ricerca:"
#: relevanssi.php:1502
msgid "Enter a comma-separated list of category and tag IDs that are excluded from search results. This only works here, you can't use the input field option (WordPress doesn't pass custom parameters there)."
msgstr "Inserire un elenco separato da virgola, con gli id delle categorie e dei tag esclusi dai risultati della ricerca. Non è possibile sovrascrivere o cambiare questa impostazione inserendo dell'apposito codice nel modulo di ricerca."
#: relevanssi.php:1505
msgid "Exclude these posts/pages from search:"
msgstr "Escludi questi articoli/pagine dalla ricerca:"
#: relevanssi.php:1506
msgid "Enter a comma-separated list of post/page IDs that are excluded from search results. This only works here, you can't use the input field option (WordPress doesn't pass custom parameters there)."
msgstr "Inserire un elenco separato da virgola, con gli id degli articoli e/o delle pagine esclusi dai risultati della ricerca. Non è possibile sovrascrivere o cambiare questa impostazione inserendo dell'apposito codice nel modulo di ricerca."
#: relevanssi.php:1507
msgid "Index and search your posts' tags:"
msgstr "Indicizza e cerca i tag degli articoli:"
#: relevanssi.php:1508
msgid "If checked, Relevanssi will also index and search the tags of your posts. Remember to rebuild the index if you change this option!"
msgstr "Se selezionato, Relevanssi indicizzerà anche i tag degli articoli. Ricordati di ricostruire l'indice se cambi questa opzione!"
#: relevanssi.php:1509
msgid "Index and search these comments:"
msgstr "Indicizza e ricerca questi commenti:"
#: relevanssi.php:1510
msgid "Relevanssi will index and search ALL (all comments including track- &amp; pingbacks and custom comment types), NONE (no comments) or NORMAL (manually posted comments on your blog).<br />Remember to rebuild the index if you change this option!"
msgstr "Relevanssi consente di indicizzare e di effettuare le ricerche su TUTTO (compresi tutti i commenti, track & pingbacks e i commenti personalizzati), NESSUNO (commenti esclusi) o NORMALE (solo i commenti inseriti manualmente nel tuo blog). <br /> Ricordati di ricostruire l'indice, se modifichi questa opzione!"
#: relevanssi.php:1511
msgid "all"
msgstr "tutto"
#: relevanssi.php:1512
msgid "normal"
msgstr "normale"
#: relevanssi.php:1513
msgid "none"
msgstr "nessuno"
#: relevanssi.php:1516
msgid "Create custom search result snippets:"
msgstr "Crea un frammento di ricerca personalizzato:"
#: relevanssi.php:1517
msgid "If checked, Relevanssi will create excerpts that contain the search term hits. To make them work, make sure your search result template uses the_excerpt() to display post excerpts."
msgstr "Se selezionato, Relevanssi creerà un estratto che conterrà la parola cercata. Affinché funzioni, assicurarsi che il template utilizzi la funzione the_excerpt() per visualizzare il risultato della ricerca."
#: relevanssi.php:1518
msgid "Length of the snippet:"
msgstr "Lunghezza del frammento:"
#: relevanssi.php:1519
msgid "This must be an integer."
msgstr "Deve essere un numero intero."
#: relevanssi.php:1520
msgid "words"
msgstr "parole"
#: relevanssi.php:1521
msgid "characters"
msgstr "caratteri"
#: relevanssi.php:1522
msgid "Keep a log of user queries:"
msgstr "Conserva un log delle ricerche:"
#: relevanssi.php:1523
msgid "If checked, Relevanssi will log user queries."
msgstr "Se selezionato, Relevanssi terrà traccia delle ricerche effettuate."
#: relevanssi.php:1524
msgid "Highlight query terms in search results:"
msgstr "Evidenzia i termini di ricerca nei risultati:"
#: relevanssi.php:1525
msgid "Highlighting isn't available unless you use custom snippets"
msgstr "L'evidenziazione non è disponibile se non si utilizzano degli snippet personalizzati"
#: relevanssi.php:1526
msgid "Highlight query terms in result titles too:"
msgstr "Evidenzia i termini di ricerca anche nei titoli dei risultati:"
#: relevanssi.php:1529
msgid "Save"
msgstr "Salva"
#: relevanssi.php:1530
msgid "Building the index and indexing options"
msgstr "Costruisci l'indice e salva le opzioni di indicizzazione"
#: relevanssi.php:1531
msgid "After installing the plugin, you need to build the index. This generally needs to be done once, you don't have to re-index unless something goes wrong. Indexing is a heavy task and might take more time than your servers allow. If the indexing cannot be finished - for example you get a blank screen or something like that after indexing - you can continue indexing from where you left by clicking 'Continue indexing'. Clicking 'Build the index' will delete the old index, so you can't use that."
msgstr "Dopo aver installato il plugin, è necessario costruire l'indice. Questo genere deve essere fatto una volta solo e non si deve reindicizzare fino a che qualcosa non funziona bene. L'indicizzazione è un compito pesante e potrebbe richiedere più tempo di quanto i server consentono. Se l'indicizzazione non viene completata e si ottine ad esempio una pagina bianca o qualcosa del genere, è possibile continuare l'indicizzazione dal punto in cui è stata interrotta semplicemente premendo il tasto 'Continua indicizzazione'. Cliccando invece su 'costruisci l'indice' si reinizierà da zero la creazione dell'indicie."
#: relevanssi.php:1532
msgid "So, if you build the index and don't get the 'Indexing complete' in the end, keep on clicking the 'Continue indexing' button until you do. On my blogs, I was able to index ~400 pages on one go, but had to continue indexing twice to index ~950 pages."
msgstr "Se si crea l'indice e alla fine non si ottiene il risultato di 'indicizzazione completa', cliccare nuovamente sul pulsante 'Continua indicizzazione' fino a quando non si otterrà tale risultato. Il mo blog ad esempio è stato in grado di indicizzare circa 400 pagine in una volta sola, ma ha dovuto continuare l'indicizzazione due volte per completare l'indice di circa 950 pagine."
#: relevanssi.php:1533
msgid "Save indexing options and build the index"
msgstr "Salva le opzioni di indicizzazione e costruisci l'indice"
#: relevanssi.php:1534
msgid "Continue indexing"
msgstr "Continua indicizzazione"
#: relevanssi.php:1535
msgid "No highlighting"
msgstr "No evidenziazione"
#: relevanssi.php:1536
msgid "Text color"
msgstr "Colore del testo"
#: relevanssi.php:1537
msgid "Background color"
msgstr "Colore di sfondo"
#: relevanssi.php:1538
msgid "CSS Style"
msgstr "Stile CSS"
#: relevanssi.php:1539
msgid "CSS Class"
msgstr "Classe CSS"
#: relevanssi.php:1541
msgid "Text color for highlights:"
msgstr "Colore del testo delle evidenziazioni:"
#: relevanssi.php:1542
msgid "Background color for highlights:"
msgstr "Colore di sfondo delle evidenziazioni:"
#: relevanssi.php:1543
msgid "CSS style for highlights:"
msgstr "Stile CSS per le evidenziazioni:"
#: relevanssi.php:1544
msgid "CSS class for highlights:"
msgstr "Classe CSS per le evidenziazioni:"
#: relevanssi.php:1546
#: relevanssi.php:1547
msgid "Use HTML color codes (#rgb or #rrggbb)"
msgstr "Usare il codice colore HTML (#rgb o #rrggbb)"
#: relevanssi.php:1548
msgid "You can use any CSS styling here, style will be inserted with a &lt;span&gt;"
msgstr "È possibile usare qualsiasi stile CSS, lo stile sarà inserito con &lt;span&gt;"
#: relevanssi.php:1549
msgid "Name a class here, search results will be wrapped in a &lt;span&gt; with the class"
msgstr "Nome della classe qui. I risultati di ricerca saranno compresi in &lt;span&gt; con la classe"
#: relevanssi.php:1551
msgid "What to include in the index"
msgstr "Cosa includere nell'indice"
#: relevanssi.php:1552
msgid "Everything"
msgstr "Ogni cosa"
#: relevanssi.php:1553
msgid "Just posts"
msgstr "Solo articoli"
#: relevanssi.php:1554
msgid "Just pages"
msgstr "Solo pagine"
#: relevanssi.php:1556
msgid "Custom fields to index:"
msgstr "Campi personalizzati da indicizzare:"
#: relevanssi.php:1557
msgid "A comma-separated list of custom field names to include in the index."
msgstr "Una lista separata da virgola dei nomi personalizzati da includere nell'indice."
#: relevanssi.php:1559
msgid "Show breakdown of search hits in excerpts:"
msgstr "Viusalizza un separatore nei risultati di ricerca:"
#: relevanssi.php:1560
msgid "Check this to show more information on where the search hits were made. Requires custom snippets to work."
msgstr "Seleziona qui per mostrare più informazioni o per definire dove sarà effettuata la ricerca. Per attivarlo richiede uno snippet personalizzato."
#: relevanssi.php:1561
msgid "The breakdown format:"
msgstr "Formato dell'interruzione:"
#: relevanssi.php:1562
msgid "Use %body%, %title%, %tags%, %comments% and %score% to display the number of hits and the document weight."
msgstr "Usa %body%, %title%, %tags%, %comments% e %score% per visualizzare il numero di ricorrenze e il peso del documento."
#: relevanssi.php:1564
msgid "When to use fuzzy matching?"
msgstr "Quando usare la ricerca per parola simile?"
#: relevanssi.php:1565
msgid "When straight search gets no hits"
msgstr "Quando la ricerca regolare non produce risultati"
#: relevanssi.php:1566
msgid "Always"
msgstr "Sempre"
#: relevanssi.php:1567
msgid "Don't use fuzzy search"
msgstr "Non usare la ricerca per similitudini"
#: relevanssi.php:1568
msgid "Straight search matches just the term. Fuzzy search matches everything that begins or ends with the search term."
msgstr "La ricerca regolare cerca semplicemente un termine. La ricerca per similitudine trova anche tutti i termini che iniziano o finiscono come il termine di ricerca."

View File

@@ -1,578 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: Relevanssi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Pedro Padron <ppadron@w3p.com.br>\n"
"Language-Team: W3P Projetos Web <contato@w3p.com.br>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Portuguese\n"
"X-Poedit-Country: BRAZIL\n"
"X-Poedit-Basepath: /\n"
"X-Poedit-SearchPath-0: /home/ppadron/Projects/wordpress-vanilla/wp-content/plugins/relevanssi\n"
#: relevanssi.php:1032
msgid "There is no excerpt because this is a protected post."
msgstr "Não há resumo porque esse é um post protegido."
#: relevanssi.php:1746
msgid "Relevanssi Search Options"
msgstr "Opções de Busca do Relevanssi"
#: relevanssi.php:1915
msgid "25 most common words in the index"
msgstr "25 palavras mais comuns no &iacute;ndice"
#: relevanssi.php:1917
msgid "These words are excellent stopword material. A word that appears in most of the posts in the database is quite pointless when searching. This is also an easy way to create a completely new stopword list, if one isn't available in your language. Click the icon after the word to add the word to the stopword list. The word will also be removed from the index, so rebuilding the index is not necessary."
msgstr "Estas palavras são excelentes para formar uma lista de stopwords. Uma palavra que aparece na maioria dos posts é um tanto quanto inútil em uma busca. Esta também é uma maneira fácil de criar uma nova lista de stopwords, caso uma não esteja disponível em seu idioma. Clique no ícone após a palavra para adicioná-la à lista de stopwords. A palavra também será removida do índice, então não é necessário reconstruí-lo."
#: relevanssi.php:1940
msgid "Add to stopwords"
msgstr "Adicionar à lista de stopwords"
#: relevanssi.php:1953
msgid "25 most popular queries"
msgstr "25 buscas mais populares"
#: relevanssi.php:1965
msgid "Recent queries that got 0 hits"
msgstr "Buscas recentes que não retornaram resultados"
#: relevanssi.php:2126
msgid "Title boost:"
msgstr "Prioridade do Título:"
#: relevanssi.php:2135
msgid "Use search for admin:"
msgstr "Usar a busca para o admin:"
#: relevanssi.php:2138
msgid "Restrict search to these categories and tags:"
msgstr "Restringir a busca para essas categorias e tags:"
#: relevanssi.php:2182
msgid "Create custom search result snippets:"
msgstr "Criar resumos de resultado de busca personalizados:"
#: relevanssi.php:2186
msgid "Length of the snippet:"
msgstr "Tamanho do resumo:"
#: relevanssi.php:2190
msgid "Keep a log of user queries:"
msgstr "Manter um histórico de buscas dos usuários:"
#: relevanssi.php:2191
msgid "If checked, Relevanssi will log user queries."
msgstr "Se ativada, Relevanssi irá armazenar as buscas feitas pelos usuários."
#: relevanssi.php:2195
msgid "Highlight query terms in search results:"
msgstr "Usar efeito marca-texto nos termos da busca nos resultados:"
#: relevanssi.php:2196
msgid "Highlighting isn't available unless you use custom snippets"
msgstr "Esta opção só está disponível se você utilizar resumos de resultados de busca personalizados"
#: relevanssi.php:2214
msgid "Continue indexing"
msgstr "Continuar Indexação"
#: relevanssi.php:2215
msgid "No highlighting"
msgstr "Sem efeito marca-texto"
#: relevanssi.php:2216
msgid "Text color"
msgstr "Cor do texto"
#: relevanssi.php:2217
msgid "Background color"
msgstr "Cor de fundo"
#: relevanssi.php:2218
msgid "CSS Style"
msgstr "CSS Style"
#: relevanssi.php:2219
msgid "CSS Class"
msgstr "Classe CSS"
#: relevanssi.php:2221
msgid "Text color for highlights:"
msgstr "Cor de texto para efeito marca-texto:"
#: relevanssi.php:2222
msgid "Background color for highlights:"
msgstr "Cor de fundo para efeito marca-texto:"
#: relevanssi.php:2223
msgid "CSS style for highlights:"
msgstr "Estilo CSS para efeito marca-texto:"
#: relevanssi.php:2224
msgid "CSS class for highlights:"
msgstr "Classe CSS para efeito marca-texto:"
#: relevanssi.php:2226
#: relevanssi.php:2227
msgid "Use HTML color codes (#rgb or #rrggbb)"
msgstr "Use cores em hexadecimal (#rgb ou #rrggbb)"
# @ default
#: relevanssi.php:94
#, php-format
msgid "Relevanssi needs attention: Remember to build the index (you can do it at <a href=\"%1$s\">the settings page</a>), otherwise searching won't work."
msgstr "Relevanssi precisa de atenção: Lembre-se de construir o índice (você pode fazê-lo na <a href=\"%1$s\">página de opções</a>), caso contrário a busca não irá funcionar."
#: relevanssi.php:1430
msgid "Indexing complete!"
msgstr "Indexação concluída!"
#: relevanssi.php:1903
#, php-format
msgid "<div id='message' class='update fade'><p>Term '%s' added to stopwords!</p></div>"
msgstr "<div id='message' class='update fade'><p>Termo '%s' adicionado à lista de stopwords!</p></div>"
#: relevanssi.php:1906
#, php-format
msgid "<div id='message' class='update fade'><p>Couldn't add term '%s' to stopwords!</p></div>"
msgstr "<div id='message' class='update fade'><p>Não foi possível adicionar '%s' à lista de stopwords!</p></div>"
#: relevanssi.php:2129
msgid "Tag boost:"
msgstr "Prioridade da Tag:"
#: relevanssi.php:2132
msgid "Comment boost:"
msgstr "Prioridade dos Comentários:"
#: relevanssi.php:2143
msgid "Exclude these categories and tags from search:"
msgstr "Excluir da busca essas categorias e tags:"
# @ relevanssi
#: relevanssi.php:2147
msgid "Exclusions and restrictions"
msgstr "Restrições"
#: relevanssi.php:2150
msgid "Exclude these posts/pages from search:"
msgstr "Excluir esses posts/páginas da busca:"
#: relevanssi.php:2154
msgid "Index and search your posts' tags:"
msgstr "Indexar e buscar as tags dos posts:"
#: relevanssi.php:2157
msgid "Index and search these comments:"
msgstr "Indexar e buscar nestes Comentários:"
#: relevanssi.php:2162
msgid "all"
msgstr "todos"
#: relevanssi.php:2163
msgid "normal"
msgstr "normal"
#: relevanssi.php:2164
msgid "none"
msgstr "nenhum"
#: relevanssi.php:2181
msgid "Custom excerpts/snippets"
msgstr "Resumos de resultado de busca personalizados"
#: relevanssi.php:2187
msgid "This must be an integer."
msgstr "O valor deve ser um número inteiro."
#: relevanssi.php:2188
msgid "words"
msgstr "palavras"
#: relevanssi.php:2189
msgid "characters"
msgstr "caracteres"
#: relevanssi.php:2192
msgid "Search hit highlighting"
msgstr "Efeito marca-texto"
# @ relevanssi
#: relevanssi.php:2193
msgid "First, choose the type of highlighting used:"
msgstr "Primeiramente, escolha o tipo de efeito marca-texto a ser utilizado:"
# @ relevanssi
#: relevanssi.php:2194
msgid "Then adjust the settings for your chosen type:"
msgstr "Ajuste as opções para o tipo escolhido:"
#: relevanssi.php:2198
msgid "Highlight query terms in result titles too:"
msgstr "Usar efeito marca-texto também nos títulos dos resultados:"
# @ relevanssi
#: relevanssi.php:2201
msgid "Save the options"
msgstr "Gravar as opções"
#: relevanssi.php:2202
msgid "Building the index and indexing options"
msgstr "Construindo o índice e opções de indexação"
#: relevanssi.php:2213
msgid "Save indexing options and build the index"
msgstr "Gravar opções de indexação e construir o índice"
#: relevanssi.php:2233
msgid "What to include in the index"
msgstr "O que incluir no índice"
#: relevanssi.php:2234
msgid "Everything"
msgstr "Tudo"
#: relevanssi.php:2235
msgid "Just posts"
msgstr "Apenas posts"
#: relevanssi.php:2236
msgid "Just pages"
msgstr "Apenas páginas"
#: relevanssi.php:2251
msgid "Custom fields to index:"
msgstr "Campos personalizados a serem indexados:"
#: relevanssi.php:2259
msgid "Show breakdown of search hits in excerpts:"
msgstr "Exibir mais informações de hits no resumo:"
#: relevanssi.php:2262
msgid "The breakdown format:"
msgstr "Formato das informações:"
#: relevanssi.php:2267
msgid "When to use fuzzy matching?"
msgstr "Quando utilizar busca fuzzy"
#: relevanssi.php:2268
msgid "When straight search gets no hits"
msgstr "Quando a busca direta não encontra resultados"
#: relevanssi.php:2269
msgid "Always"
msgstr "Sempre"
#: relevanssi.php:2270
msgid "Don't use fuzzy search"
msgstr "Não utilizar busca fuzzy"
# @ relevanssi
#: relevanssi.php:311
msgid "Data wiped clean, you can now delete the plugin."
msgstr "Dados removidos! Você pode remover o plugin agora."
# @ relevanssi
#: relevanssi.php:2280
msgid "Uninstall"
msgstr "Desinstalar"
# @ relevanssi
#: relevanssi.php:2284
msgid "Remove plugin data"
msgstr "Remover todos os dados do plugin"
# @ relevanssi
#: relevanssi.php:2274
msgid "Expand shortcodes in post content:"
msgstr "Converter os shortcodes "
#: relevanssi.php:2167
msgid "Index and search your posts' categories:"
msgstr "Indexar e buscar as categorias dos posts:"
#: relevanssi.php:2243
msgid "Custom post types to index"
msgstr "Tipos de Posts (custom post types) a serem indexados"
#: relevanssi.php:2255
msgid "Custom taxonomies to index:"
msgstr "Taxonomias personalizadas a serem indexadas:"
#: relevanssi.php:2127
#, php-format
msgid ""
"Default: %d. 0 means titles are ignored, 1 means no boost, more\n"
"\t\tthan 1 gives extra value."
msgstr "Padrão: %d. 0 significa que os títulos são ignorados, 1 significa nenhuma prioridade, mais de 1 aumenta a prioridade."
#: relevanssi.php:2130
#, php-format
msgid ""
"Default: %d. 0 means tags are ignored, 1 means no boost, more\n"
"\t\tthan 1 gives extra value."
msgstr "Padrão: %d. 0 significa que as tags são ignoradas, 1 significa nenhuma prioridade, mais de 1 aumenta a prioridade."
#: relevanssi.php:2133
#, php-format
msgid ""
"Default: %d. 0 means comments are ignored, 1 means no boost,\n"
"\t\tmore than 1 gives extra value."
msgstr "Padrão: %d. 0 significa que os comentários são ignorados, 1 significa nenhuma prioridade, mais de 1 aumenta a prioridade."
#: relevanssi.php:2136
msgid ""
"If checked, Relevanssi will be used for searches in the admin\n"
"\t\tinterface"
msgstr "Se a opção estiver marcada, Relevanssi será usado nas buscas no painel do admin"
#: relevanssi.php:2139
msgid ""
"Enter a comma-separated list of category and tag IDs to restrict search to\n"
"\t\tthose categories or tags. You can also use <code>&lt;input type='hidden' name='cat'\n"
"\t\tvalue='list of cats and tags' /&gt;</code> in your search form. The input field will\n"
"\t\toverrun this setting."
msgstr "Insira uma lista separada por vírgulas de categorias e IDs de tags para restringir a busca apenas nelas. Você também pode usar <code>&lt;input type='hidden' name='cat' value='lista de categorias e tags' /&gt;</code> em seu formulário. O campo no formulário tem prioridade sobre esta opção no painel."
#: relevanssi.php:2144
msgid ""
"Enter a comma-separated list of category and tag IDs that are excluded from\n"
"\t\tsearch results. This only works here, you can't use the input field option (WordPress\n"
"\t\tdoesn't pass custom parameters there)."
msgstr "Insira uma lista separada por vírgulas de categorias e IDs de tags que serão excluídos dos resultados da busca. Essa opção só pode ser definida aqui, você não pode usar um campo adicional no formulário (WordPress não passa parâmetros personalizados lá)."
#: relevanssi.php:2151
msgid ""
"Enter a comma-separated list of post/page IDs that are excluded from search\n"
"\t\tresults. This only works here, you can't use the input field option (WordPress doesn't pass\n"
"\t\tcustom parameters there)."
msgstr "Insira uma lista separada por vírgulas de IDs de posts/páginas que serão excluídos dos resultados da busca. Essa opção só pode ser definida aqui, você não pode usar um campo adicional no formulário (WordPress não passa parâmetros personalizados lá)."
#: relevanssi.php:2155
msgid ""
"If checked, Relevanssi will also index and search the tags of your posts.\n"
"\t\tRemember to rebuild the index if you change this option!"
msgstr "Se esta opção estiver marcada, Relevanssi irá indexar e realizar buscas nas tags de seus posts. Lembre-se de reconstruir o índice se você mudar esta opção!"
#: relevanssi.php:2158
msgid ""
"Relevanssi will index and search ALL (all comments including track-\n"
"\t\t&amp; pingbacks and custom comment types), NONE (no comments) or NORMAL (manually posted\n"
"\t\tcomments on your blog).<br />Remember to rebuild the index if you change this option!"
msgstr "Relevanssi irá indexar e buscar em TODOS (comentários, trackbacks, pingbacks e tipos personalizados de comentários), NENHUM (nenhum comentário) ou NORMAL (comentários postados manualmente no blog).<br/> Lembre-se de reconstruir o índice se você mudar esta opção!"
#: relevanssi.php:2168
msgid ""
"If checked, Relevanssi will also index and search the categories of your\n"
"\t\tposts. Category titles will pass through 'single_cat_title' filter. Remember to rebuild the\n"
"\t\tindex if you change this option!"
msgstr "Se esta opção estiver marcada, Relevanssi irá indexar e realizar buscas nas categorias de seus posts. Lembre-se de reconstruir o índice se você mudar esta opção!"
#: relevanssi.php:2183
msgid ""
"If checked, Relevanssi will create excerpts that contain the search term\n"
"\t\thits. To make them work, make sure your search result template uses the_excerpt() to\n"
"\t\tdisplay post excerpts."
msgstr "Se esta opção estiver marcada, Relevanssi irá criar resumos que contém o(s) termo(s) buscado(s). Para que isso funcione, certifique-se de que seu template de resultado de busca utiliza <code>the_excerpt()</code> para exibir resumos de posts."
#: relevanssi.php:2203
msgid ""
"After installing the plugin, you need to build the index. This generally needs\n"
"\t\tto be done once, you don't have to re-index unless something goes wrong. Indexing is a heavy\n"
"\t\ttask and might take more time than your servers allow. If the indexing cannot be finished -\n"
"\t\tfor example you get a blank screen or something like that after indexing - you can continue\n"
"\t\tindexing from where you left by clicking 'Continue indexing'. Clicking 'Build the index'\n"
"\t\twill delete the old index, so you can't use that."
msgstr "Após a instalação do plugin, é preciso construir o índice. Isso normalmente precisa ser feito apenas uma vez. Não é necessário reconstruir o índice a não ser que algo de errado aconteça. A indexação é uma tarefa pesada e pode levar mais tempo do que seus servidores permitam. Se a indexação não puder ser concluída - por exemplo, você encontrar uma tela branca ou algo parecido após a indexação - você pode continuar o processo a partir de onde parou ao clicar em \"Continuar Indexação\". Ao clicar em \"Construir o Índice\" o índice atual será removido, portanto não clique nele para continuar uma indexação interrompida."
#: relevanssi.php:2209
msgid ""
"So, if you build the index and don't get the 'Indexing complete' in the end,\n"
"\t\tkeep on clicking the 'Continue indexing' button until you do. On my blogs, I was able to\n"
"\t\tindex ~400 pages on one go, but had to continue indexing twice to index ~950 pages."
msgstr "Portanto, se você construir o índice e não receber a mensagem \"Indexação Concluída\" no final, continue clicando em \"Continuar Indexação\" até que isso aconteça. Em meus blogs consegui indexar cerca de 400 páginas de uma só vez, mas precisei continuar o processo mais duas vezes para chegar a cerca de 950 páginas."
#: relevanssi.php:2228
msgid ""
"You can use any CSS styling here, style will be inserted with a\n"
"\t\t&lt;span&gt;"
msgstr "Você pode usar qualquer estilo CSS aqui, ele será inserido com a tag <code>&lt;span&gt;</code>"
#: relevanssi.php:2230
msgid ""
"Name a class here, search results will be wrapped in a &lt;span&gt;\n"
"\t\twith the class"
msgstr "Insira aqui o nome da classe e os resultados da busca serão encapsulados por uma tag <code>&lt;span&gt;</code> com esta classe"
# @ relevanssi
#: relevanssi.php:2237
msgid "All public post types"
msgstr "Todos os tipos de post públicos"
# @ relevanssi
#: relevanssi.php:2238
msgid ""
"This determines which post types are included in the index. Choosing\n"
"\t\t'everything' will include posts, pages and all custom post types. 'All public post types'\n"
"\t\tincludes all registered post types that don't have the 'exclude_from_search' set to true.\n"
"\t\tThis includes post, page, attachment, and possible custom types. 'All public types'\n"
"\t\trequires at least WP 2.9, otherwise it's the same as 'everything'."
msgstr "Isso determina quais tipos de posts serão indexados. Ao escolher \"Tudo\" serão incluídos todos os posts, páginas e posts personalizados. \"Todos os tipos de post públicos\" inclui todos os tipos de posts públicos que não possuam o atributo \"exclude_from_search\" definido como verdadeiro, o que inclui posts, páginas, anexos e possivelmente posts personalizados. A opção \"Todos os tipos de post públicos\" requer Wordpress 2.9 ou superior, caso contrário será o mesmo que \"Tudo\"."
# @ relevanssi
#: relevanssi.php:2244
msgid ""
"If you don't want to index all custom post types, list here the custom\n"
"\t\tpost types you want to see indexed. List comma-separated post type names (as used in the\n"
"\t\tdatabase). You can also use a hidden field in the search form to restrict the search to a\n"
"\t\tcertain post type: <code>&lt;input type='hidden' name='post_type' value='comma-separated\n"
"\t\tlist of post types' /&gt;</code>. If you choose 'All public post types' or 'Everything'\n"
"\t\tabove, this option has no effect."
msgstr "Se você não quiser indexar todos os tipos de post personalizados, liste aqui quais são os tipos que você quer indexar. Insira os nomes dos tipos de posts em uma lista separada por vírgula. Você pode também usar um campo hidden no formário de busca para restringir a busca em um determinado tipo de post: <code>&lt;input type='hidden' name='post_type' value='lista de tipos de posts' /&gt;</code>. Se na opção anterior você escolheu \"Todos os tipos de posts públicos\" ou \"Tudo\", essa opção não terá efeito."
#: relevanssi.php:2252
msgid ""
"A comma-separated list of custom field names to include in the\n"
"\t\tindex."
msgstr "Uma lista separada por vírgula de nomes de campos personalizados a serem incluídos no índice."
#: relevanssi.php:2256
msgid ""
"A comma-separated list of custom taxonomies to include in the\n"
"\t\tindex."
msgstr "Uma lista separada por vírgula de nomes de taxonomias personalizadas a serem incluídos no índice."
#: relevanssi.php:2260
msgid ""
"Check this to show more information on where the search hits were\n"
"\t\tmade. Requires custom snippets to work."
msgstr "Marque esta opção para exibir mais informações sobre onde os termos buscados foram encontrados. Para essa opção funcionar, é preciso habilitar os resumos personalizados."
#: relevanssi.php:2271
msgid ""
"Straight search matches just the term. Fuzzy search matches everything\n"
"\t\tthat begins or ends with the search term."
msgstr "Busca direta encontra apenas o termo buscado. Busca fuzzy irá encontrar tudo que começa ou termina com o termo buscado."
# @ relevanssi
#: relevanssi.php:2275
msgid ""
"If checked, Relevanssi will expand shortcodes in post content\n"
"\t\tbefore indexing. Otherwise shortcodes will be stripped. If you use shortcodes to\n"
"\t\tinclude dynamic content, Relevanssi will not keep the index updated, the index will\n"
"\t\treflect the status of the shortcode content at the moment of indexing."
msgstr "Se esta opção estiver marcada, Relevanssi irá converter os shortcodes no conteúdo do post antes de indexar. Caso contrário, os shortcodes serão removidos. Se você utiliza shortcodes para incluir conteúdo dinâmico, Relevanssi não manterá o índice atualizado. Ou seja, será utilizado o conteúdo gerado pelo shortcode no momento da indexação."
# @ relevanssi
#: relevanssi.php:2281
msgid ""
"If you want to uninstall the plugin, start by clicking the button\n"
"\t\tbelow to wipe clean the options and tables created by the plugin, then remove it from\n"
"\t\tthe plugins list."
msgstr "Se quiser desinstalar o plugin, comece clicando no botão abaixo para remover todas as opções e todas as tabelas criadas pelo plugin, e então remova-o da lista de plugins."
#: relevanssi.php:2172
msgid "Index and search your posts' authors:"
msgstr "Indexar e buscar os autores dos posts:"
#: relevanssi.php:2173
msgid ""
"If checked, Relevanssi will also index and search the authors of your\n"
"\t\tposts. Author display name will be indexed. Remember to rebuild the index if you change\n"
"\t\tthis option!"
msgstr "Se esta opção estiver marcada, Relevanssi irá indexar e realizar buscas nos autores de seus posts. Lembre-se de reconstruir o índice se você mudar esta opção!"
# @ relevanssi
#: relevanssi.php:2286
msgid "State of the Index"
msgstr "Estatísticas do Índice"
# @ relevanssi
#: relevanssi.php:2287
msgid "Highest post ID indexed"
msgstr "Último ID indexado"
#: relevanssi.php:2288
msgid "Documents in the index"
msgstr "Registros no índice"
# @ relevanssi
#: relevanssi.php:2289
msgid "Basic options"
msgstr "Opções Básicas"
# @ relevanssi
#: relevanssi.php:2291
msgid "Default operator for the search?"
msgstr "Operador padrão para a busca?"
# @ relevanssi
#: relevanssi.php:2292
msgid "AND - require all terms"
msgstr "E - necessita de todos os termos"
# @ relevanssi
#: relevanssi.php:2293
msgid "OR - any term present is enough"
msgstr "OU - qualquer termo presente é o bastante"
# @ relevanssi
#: relevanssi.php:2294
msgid "If you choose AND and the search finds no matches, it will automatically do an OR search."
msgstr "Se escolher E e a busca não encontrar resultados, uma nova busca do tipo OU será feita automaticamente."
# @ relevanssi
#: relevanssi.php:2296
msgid "Don't log queries from these users:"
msgstr "Não armazenar registros de buscas destes usuários:"
#: relevanssi.php:2297
msgid "Comma-separated list of user ids that will not be logged."
msgstr "Uma lista separada por vírgula de usuários que não terão suas buscas registradas."
# @ relevanssi
#: relevanssi.php:2299
msgid "Synonyms"
msgstr "Sinônimos"
# @ relevanssi
#: relevanssi.php:2300
msgid "Add synonyms here in 'key = value' format. When searching with the OR operator, any search of 'key' will be expanded to include 'value' as well. Using phrases is possible. The key-value pairs work in one direction only, but you can of course repeat the same pair reversed."
msgstr "Adicione sinônimos no formato \"chave = valor\". Quando for feita uma busca do tipo OU, qualquer busca por <strong>\"chave\"</strong> será expandida para incluir <strong>\"valor\"</strong> também. É possível utilizar frases. Os pares chave-valor funcionam apenas em uma direção, mas claro que você pode repetir o mesmo par em ordem inversa."
#: relevanssi.php:2177
msgid "Index and search post excerpts:"
msgstr "Indexar e buscar os resumos dos posts:"
#: relevanssi.php:2178
msgid ""
"If checked, Relevanssi will also index and search the excerpts of your\n"
"\t\tposts.Remember to rebuild the index if you change this option!"
msgstr "Se esta opção estiver marcada, Relevanssi irá indexar e realizar buscas nos resumos de seus posts. Lembre-se de reconstruir o índice se você mudar esta opção!"
# @ relevanssi
#: relevanssi.php:2263
#, php-format
msgid ""
"Use %body%, %title%, %tags% and %comments% to display the number of\n"
"\t\thits (in different parts of the post), %total% for total hits, %score% to display the document weight and %terms% to\n"
"\t\tshow how many hits each search term got. No double quotes (\") allowed!"
msgstr "Utilize %body%, %title%, %tags% e %comments% para exibir o número de hits, %total% para o total de hits, %score% para exibir a relevância e %terms% para exibir quantas vezes cada termo buscado foi encontrado. Aspas duplas (\") não são permitidas aqui!"
#~ msgid "Save"
#~ msgstr "Gravar"
#~ msgid ""
#~ "Use %body%, %title%, %tags%, %comments% and %score% to display the number "
#~ "of hits and the document weight."
#~ msgstr ""
#~ "Use %body%, %title%, %tags%, %comments% e %score% para exibir o número de "
#~ "hits e o peso do resultado."

View File

@@ -1,148 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Mikko Saari <mikko@mikkosaari.fi>\n"
"Language-Team: \n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/index.js:151
msgid "not this"
msgstr "ei tätä"
#: src/index.js:174
msgid "use this"
msgstr "käytä tätä"
#: src/index.js:199
msgid "How Relevanssi sees this post"
msgstr "Kuinka Relevanssi näkee artikkelin"
#: src/index.js:203
msgid "Title:"
msgstr "Otsikko:"
#: src/index.js:210
msgid "Content:"
msgstr "Sisältö:"
#: src/index.js:217
msgid "Author:"
msgstr "Tekijä:"
#: src/index.js:224
msgid "Categories:"
msgstr "Aiheet:"
#: src/index.js:231
msgid "Tags:"
msgstr "Avainsanat:"
#: src/index.js:238
msgid "Other taxonomies:"
msgstr "Muut taksonomiat:"
#: src/index.js:245
msgid "Comments:"
msgstr "Kommentit:"
#: src/index.js:252
msgid "Custom fields:"
msgstr "Avainkentät:"
#: src/index.js:259
msgid "Excerpt:"
msgstr "Ote:"
#: src/index.js:266
msgid "Links to this post:"
msgstr "Sisäiset linkit:"
#: src/index.js:273
msgid "MySQL columns:"
msgstr "MySQL-sarakkeet:"
#: src/index.js:281
msgid "Reason this post is not indexed:"
msgstr "Miksi tätä artikkelia ei ole indeksoitu:"
#: src/index.js:290
msgid "Pinning"
msgstr "Artikkelin kiinnittäminen"
#: src/index.js:294
msgid "Pin this post for all searches it appears in."
msgstr "Kiinnitä tämä artikkeli kärkeen kaikissa hauissa, joissa se esiintyy."
#: src/index.js:304
msgid ""
"A comma-separated list of single word keywords or multi-word phrases. If any "
"of these keywords are present in the search query, this post will be moved "
"on top of the search results."
msgstr ""
"Pilkuilla erotettu lista yksittäisiä hakusanoja tai monisanaisia "
"hakulauseita. Jos joku näistä hakusanoista esiintyy käyttäjän haussa, tämä "
"artikkeli kiinnitetään hakutulosten huipulle."
#: src/index.js:314
msgid "Exclusion"
msgstr "Artikkelien poissulkeminen"
#: src/index.js:319
msgid "Exclude this post or page from the index."
msgstr "Poista tämä artikkeli indeksistä."
#: src/index.js:329
msgid ""
"A comma-separated list of single word keywords or multi-word phrases. If any "
"of these keywords are present in the search query, this post will be removed "
"from the search results."
msgstr ""
"Pilkuilla erotettu lista yksittäisiä hakusanoja tai monisanaisia "
"hakulauseita. Jos joku näistä hakusanoista esiintyy käyttäjän haussa, tämä "
"artikkeli poistetaan hakutuloksista."
#: src/index.js:341
msgid "Related posts"
msgstr "Aiheeseen liittyvät artikkelit"
#: src/index.js:346
msgid "Don't append the related posts to this page."
msgstr "Älä lisää samankaltaisia artikkeleita tälle sivulle."
#: src/index.js:356
msgid "Don't show this as a related post for any post."
msgstr "Älä näytä tätä samankaltaisena artikkelina millään sivulla."
#: src/index.js:366
msgid ""
"A comma-separated list of keywords to use for the Related Posts feature. "
"Anything entered here will used when searching for related posts. Using "
"phrases with quotes is allowed, but will restrict the related posts to posts "
"including that phrase."
msgstr ""
"Pilkulla erotettu lista avainsanoja samankaltaisten artikkelien etsimiseen. "
"Tähän merkittyjä hakusanoja käytetään samankaltaisten artikkelien "
"etsimiseen. Voit käyttää fraasihakua lainausmerkeillä, mutta se rajoittaa "
"samankaltaiset artikkelit niihin, joissa fraasi esiintyy."
#: src/index.js:376
msgid ""
"A comma-separated list of post IDs to use as related posts for this post"
msgstr ""
"Pilkuilla erotettu lista tämän artikkelin liittyvinä artikkeleina "
"käytettävien artikkelien ID-numeroista"
#: src/index.js:383
msgid "Related posts for this post:"
msgstr "Samankaltaiset artikkelit:"
#: src/index.js:386
msgid "Excluded posts for this post:"
msgstr "Älä käytä samankaltaisina artikkeleina tälle artikkelille:"

View File

@@ -1,141 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-03-18T08:08:41+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.6.0\n"
"X-Domain: relevanssi\n"
#: index.js:152
msgid "not this"
msgstr ""
#: index.js:175
msgid "use this"
msgstr ""
#: index.js:224
msgid "How Relevanssi sees this post"
msgstr ""
#: index.js:228
msgid "Title:"
msgstr ""
#: index.js:235
msgid "Content:"
msgstr ""
#: index.js:242
msgid "Author:"
msgstr ""
#: index.js:249
msgid "Categories:"
msgstr ""
#: index.js:256
msgid "Tags:"
msgstr ""
#: index.js:263
msgid "Other taxonomies:"
msgstr ""
#: index.js:270
msgid "Comments:"
msgstr ""
#: index.js:277
msgid "Custom fields:"
msgstr ""
#: index.js:284
msgid "Excerpt:"
msgstr ""
#: index.js:291
msgid "Links to this post:"
msgstr ""
#: index.js:298
msgid "MySQL columns:"
msgstr ""
#: index.js:306
msgid "Reason this post is not indexed:"
msgstr ""
#: index.js:315
msgid "Pinning"
msgstr ""
#: index.js:319
msgid "Pin this post for all searches it appears in."
msgstr ""
#: index.js:329
msgid "A comma-separated list of single word keywords or multi-word phrases. If any of these keywords are present in the search query, this post will be moved on top of the search results."
msgstr ""
#: index.js:339
msgid "Exclusion"
msgstr ""
#: index.js:344
msgid "Exclude this post or page from the index."
msgstr ""
#: index.js:354
msgid "Ignore post content in the indexing."
msgstr ""
#: index.js:364
msgid "A comma-separated list of single word keywords or multi-word phrases. If any of these keywords are present in the search query, this post will be removed from the search results."
msgstr ""
#: index.js:376
msgid "Related posts"
msgstr ""
#: index.js:381
msgid "Don't append the related posts to this page."
msgstr ""
#: index.js:391
msgid "Don't show this as a related post for any post."
msgstr ""
#: index.js:401
msgid "A comma-separated list of keywords to use for the Related Posts feature. Anything entered here will used when searching for related posts. Using phrases with quotes is allowed, but will restrict the related posts to posts including that phrase."
msgstr ""
#: index.js:411
msgid "A comma-separated list of post IDs to use as related posts for this post"
msgstr ""
#: index.js:418
msgid "Related posts for this post:"
msgstr ""
#: index.js:421
msgid "Excluded posts for this post:"
msgstr ""
#: index.js:426
msgid "Insights"
msgstr ""
#: index.js:428
msgid "The most common search terms used to find this post:"
msgstr ""
#: index.js:435
msgid "Low-ranking search terms used to find this post:"
msgstr ""

View File

@@ -1,457 +0,0 @@
<?php
/**
* /lib/admin-ajax.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'wp_ajax_relevanssi_truncate_index', 'relevanssi_truncate_index_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_index_posts', 'relevanssi_index_posts_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_count_posts', 'relevanssi_count_posts_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_count_missing_posts', 'relevanssi_count_missing_posts_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_list_categories', 'relevanssi_list_categories' );
add_action( 'wp_ajax_relevanssi_admin_search', 'relevanssi_admin_search' );
add_action( 'wp_ajax_relevanssi_update_counts', 'relevanssi_update_counts' );
add_action( 'wp_ajax_nopriv_relevanssi_update_counts', 'relevanssi_update_counts' );
/**
* Checks if current user can access Relevanssi options.
*
* If the current user doesn't have sufficient access to Relevanssi options,
* the function will die. If the user has access, nothing happens.
*
* @return void
*/
function relevanssi_current_user_can_access_options() {
/**
* Filters the capability required to access Relevanssi options.
*
* @param string The capability required. Default 'manage_options'.
*/
if ( ! current_user_can( apply_filters( 'relevanssi_options_capability', 'manage_options' ) ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'relevanssi' ) );
}
}
/**
* Truncates the Relevanssi index.
*
* Wipes the index clean using relevanssi_truncate_index().
*/
function relevanssi_truncate_index_ajax_wrapper() {
check_ajax_referer( 'relevanssi_indexing_nonce', 'security' );
relevanssi_current_user_can_access_options();
$response = relevanssi_truncate_index();
echo wp_json_encode( $response );
wp_die();
}
/**
* Indexes posts in AJAX context.
*
* AJAX wrapper for indexing posts. Parses the arguments, uses the
* relevanssi_build_index() to do the hard work, then creates the AJAX response.
*/
function relevanssi_index_posts_ajax_wrapper() {
check_ajax_referer( 'relevanssi_indexing_nonce', 'security' );
relevanssi_current_user_can_access_options();
$completed = absint( $_POST['completed'] );
$total = absint( $_POST['total'] );
$offset = absint( $_POST['offset'] );
$limit = absint( $_POST['limit'] );
$extend = strval( $_POST['extend'] );
if ( 'true' === $extend ) {
$extend = true;
}
if ( $limit < 1 ) {
$limit = 1;
}
$response = array();
$is_ajax = true;
$verbose = false;
if ( $extend ) {
$offset = true;
}
$indexing_response = relevanssi_build_index( $offset, $verbose, $limit, $is_ajax );
if ( $indexing_response['indexing_complete'] ) {
$response['completed'] = 'done';
$response['percentage'] = 100;
$completed += $indexing_response['indexed'];
$response['total_posts'] = $completed;
$processed = $total;
} else {
$completed += $indexing_response['indexed'];
$response['completed'] = $completed;
if ( true === $offset ) {
$processed = $completed;
} else {
$offset = $offset + $limit;
$processed = $offset;
}
if ( $total > 0 ) {
$response['percentage'] = $processed / $total * 100;
} else {
$response['percentage'] = 0;
}
}
$response['feedback'] = sprintf(
// translators: Number of posts indexed on this go, total number of posts indexed so far, number of posts processed on this go, total number of posts to process.
_n(
'Indexed %1$d post (total %2$d), processed %3$d / %4$d.',
'Indexed %1$d posts (total %2$d), processed %3$d / %4$d.',
$indexing_response['indexed'],
'relevanssi'
),
$indexing_response['indexed'],
$completed,
$processed,
$total
) . "\n";
$response['offset'] = $offset;
echo wp_json_encode( $response );
wp_die();
}
/**
* Counts the posts to index.
*
* AJAX wrapper for relevanssi_count_total_posts().
*/
function relevanssi_count_posts_ajax_wrapper() {
relevanssi_current_user_can_access_options();
$count = relevanssi_count_total_posts();
echo wp_json_encode( $count );
wp_die();
}
/**
* Counts the posts missing from the index.
*
* AJAX wrapper for relevanssi_count_missing_posts().
*/
function relevanssi_count_missing_posts_ajax_wrapper() {
relevanssi_current_user_can_access_options();
$count = relevanssi_count_missing_posts();
echo wp_json_encode( $count );
wp_die();
}
/**
* Lists categories.
*
* AJAX wrapper for get_categories().
*/
function relevanssi_list_categories() {
relevanssi_current_user_can_access_options();
$categories = get_categories(
array(
'taxonomy' => 'category',
'hide_empty' => false,
)
);
echo wp_json_encode( $categories );
wp_die();
}
/**
* Performs an admin search.
*
* Performs an admin dashboard search.
*
* @since 2.2.0
*/
function relevanssi_admin_search() {
check_ajax_referer( 'relevanssi_admin_search_nonce', 'security' );
/**
* Filters the capability required to access Relevanssi admin search page.
*
* @param string The capability required. Default 'edit_posts'.
*/
if ( ! current_user_can( apply_filters( 'relevanssi_admin_search_capability', 'edit_posts' ) ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'relevanssi' ) );
}
$args = array();
if ( isset( $_POST['args'] ) ) {
parse_str( $_POST['args'], $args );
}
if ( isset( $_POST['posts_per_page'] ) ) {
$posts_per_page = intval( $_POST['posts_per_page'] );
if ( $posts_per_page > 0 ) {
$args['posts_per_page'] = $posts_per_page;
}
}
if ( isset( $_POST['post_types'] ) ) {
$post_type = $_POST['post_types'];
$args['post_types'] = $post_type;
}
if ( isset( $_POST['offset'] ) ) {
$offset = intval( $_POST['offset'] );
if ( $offset > 0 ) {
$args['offset'] = $offset;
}
}
if ( isset( $_POST['s'] ) ) {
$args['s'] = $_POST['s'];
}
$query = new WP_Query();
$query->parse_query( $args );
$query->set( 'relevanssi_admin_search', true );
$query = apply_filters( 'relevanssi_modify_wp_query', $query );
relevanssi_do_query( $query );
$results = relevanssi_admin_search_debugging_info( $query );
// Take the posts array and create a string out of it.
$offset = 0;
if ( isset( $query->query_vars['offset'] ) ) {
$offset = $query->query_vars['offset'];
}
$results .= relevanssi_admin_search_format_posts( $query->posts, $query->found_posts, $offset, $args['s'] );
echo wp_json_encode( $results );
wp_die();
}
/**
* Formats the posts for admin search.
*
* Results are presented as an ordered list of posts. The format is very basic, and
* can be modified with the 'relevanssi_admin_search_element' filter hook.
*
* @param array $posts The posts array.
* @param int $total The number of posts found in total.
* @param int $offset Offset value.
* @param string $query The search query.
*
* @return string The formatted posts.
*
* @since 2.2.0
*/
function relevanssi_admin_search_format_posts( $posts, $total, $offset, $query ) {
$result = '<h3>' . __( 'Results', 'relevanssi' ) . '</h3>';
$start = $offset + 1;
$end = $offset + count( $posts );
// Translators: %1$d is the total number of posts found, %2$d is the current search result count, %3$d is the offset.
$result .= '<p>' . sprintf( __( 'Found a total of %1$d posts, showing posts %2$d%3$s.', 'relevanssi' ), $total, $start, '<span id="offset">' . $end . '</span>' ) . '</p>';
if ( $offset > 0 ) {
$result .= sprintf( '<button type="button" id="prev_page">%s</button>', __( 'Previous page', 'relevanssi' ) );
}
if ( count( $posts ) + $offset < $total ) {
$result .= sprintf( '<button type="button" id="next_page">%s</button>', __( 'Next page', 'relevanssi' ) );
}
$result .= '<ol start="' . $start . '">';
$score_label = __( 'Score:', 'relevanssi' );
foreach ( $posts as $post ) {
$blog_name = '';
if ( isset( $post->blog_id ) ) {
switch_to_blog( $post->blog_id );
$blog_name = get_bloginfo( 'name' ) . ': ';
}
$permalink = get_permalink( $post->ID );
$edit_url = get_edit_post_link( $post->ID );
$post_type = $post->post_type;
if ( isset( $post->relevanssi_link ) ) {
$permalink = $post->relevanssi_link;
}
if ( 'user' === $post->post_type ) {
$edit_url = get_edit_user_link( $post->ID );
}
if ( empty( $edit_url ) ) {
if ( isset( $post->term_id ) ) {
$edit_url = get_edit_term_link( $post->term_id, $post->post_type );
}
}
$title = sprintf( '<a href="%1$s">%2$s %3$s</a>', $permalink, $post->post_title, $post_type );
$edit_link = '';
if ( current_user_can( 'edit_post', $post->ID ) ) {
$edit_link = sprintf( '(<a href="%1$s">%2$s %3$s</a>)', $edit_url, __( 'Edit', 'relevanssi' ), $post_type );
}
$pinning_buttons = '';
$pinned = '';
if ( function_exists( 'relevanssi_admin_search_pinning' ) ) {
// Relevanssi Premium adds pinning features to the admin search.
list( $pinning_buttons, $pinned ) = relevanssi_admin_search_pinning( $post, $query );
}
$post_element = <<<EOH
<li>$blog_name <strong>$title</strong> $edit_link $pinning_buttons <br />
$post->post_excerpt<br />
$score_label $post->relevance_score $pinned</li>
EOH;
/**
* Filters the admin search results element.
*
* The post element is a <li> element. Feel free to edit the element any
* way you want to.
*
* @param string $post_element The post element.
* @param object $post The post object.
*/
$result .= apply_filters( 'relevanssi_admin_search_element', $post_element, $post );
if ( isset( $post->blog_id ) ) {
restore_current_blog();
}
}
$result .= '</ol>';
return $result;
}
/**
* Shows debugging information about the search.
*
* Formats the WP_Query parameters, looks at some filter hooks and presents the
* information in an easy-to-read format.
*
* @param WP_Query $query The WP_Query object.
*
* @return string The formatted debugging information.
*
* @since 2.2.0
*/
function relevanssi_admin_search_debugging_info( $query ) {
$result = '<div id="debugging">';
$result .= '<h3>' . __( 'Query variables', 'relevanssi' ) . '</h3>';
$result .= '<ul style="list-style: disc; margin-left: 1.5em">';
foreach ( $query->query_vars as $key => $value ) {
if ( 'tax_query' === $key ) {
$result .= '<li>tax_query:<ul style="list-style: disc; margin-left: 1.5em">';
$result .= implode(
'',
array_map(
function ( $row ) {
$result = '';
if ( is_array( $row ) ) {
foreach ( $row as $row_key => $row_value ) {
$result .= "<li>$row_key: $row_value</li>";
}
}
return $result;
},
$value
)
);
$result .= '</ul></li>';
} else {
if ( is_array( $value ) ) {
$value = relevanssi_flatten_array( $value );
}
if ( empty( $value ) ) {
continue;
}
$result .= "<li>$key: $value</li>";
}
}
if ( ! empty( $query->tax_query ) ) {
$result .= '<li>tax_query:<ul style="list-style: disc; margin-left: 1.5em">';
foreach ( $query->tax_query as $tax_query ) {
if ( ! is_array( $tax_query ) ) {
continue;
}
foreach ( $tax_query as $key => $value ) {
if ( is_array( $value ) ) {
$value = relevanssi_flatten_array( $value );
}
$result .= "<li>$key: $value</li>";
}
}
$result .= '</ul></li>';
}
$result .= '</ul>';
global $wp_filter;
$filters = array(
'relevanssi_search_ok',
'relevanssi_modify_wp_query',
'relevanssi_search_filters',
'relevanssi_where',
'relevanssi_join',
'relevanssi_fuzzy_query',
'relevanssi_exact_match_bonus',
'relevanssi_query_filter',
'relevanssi_match',
'relevanssi_post_ok',
'relevanssi_search_again',
'relevanssi_results',
'relevanssi_orderby',
'relevanssi_order',
'relevanssi_default_tax_query_relation',
'relevanssi_hits_filter',
);
$result .= '<h3>' . __( 'Filters', 'relevanssi' ) . '</h3>';
$result .= '<button type="button" id="show_filters">' . __( 'show', 'relevanssi' ) . '</button>';
$result .= '<button type="button" id="hide_filters" style="display: none">' . __( 'hide', 'relevanssi' ) . '</button>';
$result .= '<div id="relevanssi_filter_list">';
foreach ( $filters as $filter ) {
if ( isset( $wp_filter[ $filter ] ) ) {
$result .= '<h4>' . $filter . '</h4>';
$result .= '<ul style="list-style: disc; margin-left: 1.5em">';
foreach ( $wp_filter[ $filter ] as $priority => $functions ) {
foreach ( $functions as $function ) {
if ( $function['function'] instanceof Closure ) {
$function['function'] = 'Anonymous function';
}
$result .= "<li>$priority: " . $function['function'] . '</li>';
}
}
$result .= '</ul>';
}
}
$result .= '</div>';
$result .= '</div>';
return $result;
}
/**
* Updates count options.
*
* Updates 'relevanssi_doc_count', 'relevanssi_terms_count' (and in Premium
* 'relevanssi_user_count' and 'relevanssi_taxterm_count'). These are slightly
* expensive queries, so they are updated when necessary as a non-blocking AJAX
* action and stored in options for quick retrieval.
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The Relevanssi global variable, used for table names.
*/
function relevanssi_update_counts() {
global $wpdb, $relevanssi_variables;
relevanssi_update_doc_count();
$terms_count = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $relevanssi_variables['relevanssi_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
update_option( 'relevanssi_terms_count', is_null( $terms_count ) ? 0 : $terms_count, false );
if ( RELEVANSSI_PREMIUM ) {
$user_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE type = 'user'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
$taxterm_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE (type != 'post' AND type != 'attachment' AND type != 'user')" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
update_option( 'relevanssi_user_count', is_null( $user_count ) ? 0 : $user_count, false );
update_option( 'relevanssi_taxterm_count', is_null( $taxterm_count ) ? 0 : $taxterm_count, false );
}
}

View File

@@ -1,525 +0,0 @@
/* Confirmation for copying options between blogs */
jQuery(document).ready(function ($) {
$("#copy_config").submit(function () {
var c = confirm(relevanssi.confirm)
return c //you can just return c because it will be true or false
})
$("#removeallstopwords").click(function () {
var c = confirm(relevanssi.confirm_stopwords)
return c
})
$("#delete_query").click(function () {
var c = confirm(relevanssi.confirm_delete_query)
return c
})
})
jQuery(document).ready(function ($) {
$(".color-field").wpColorPicker()
var txtcol_control = $("#tr_relevanssi_txt_col")
var bgcol_control = $("#tr_relevanssi_bg_col")
var class_control = $("#tr_relevanssi_class")
var css_control = $("#tr_relevanssi_css")
$("#relevanssi_highlight").change(function () {
txtcol_control.addClass("screen-reader-text")
bgcol_control.addClass("screen-reader-text")
class_control.addClass("screen-reader-text")
css_control.addClass("screen-reader-text")
if (this.value == "col") txtcol_control.toggleClass("screen-reader-text")
if (this.value == "bgcol") bgcol_control.toggleClass("screen-reader-text")
if (this.value == "class") class_control.toggleClass("screen-reader-text")
if (this.value == "css") css_control.toggleClass("screen-reader-text")
})
$("#relevanssi_hilite_title").click(function () {
$("#title_description").toggleClass("screen-reader-text", !this.checked)
})
var or_fallback = $("#orfallback")
$("#relevanssi_implicit_operator").change(function () {
or_fallback.toggleClass("screen-reader-text")
})
var index_subscribers = $("#index_subscribers")
var user_extra_fields = $("#user_extra_fields")
$("#relevanssi_index_users").click(function () {
$("#user_profile_notice").toggleClass("screen-reader-text", !this.checked)
index_subscribers.toggleClass("screen-reader-text", !this.checked)
user_extra_fields.toggleClass("screen-reader-text", !this.checked)
})
var taxonomies = $("#taxonomies")
$("#relevanssi_index_taxonomies").click(function () {
taxonomies.toggleClass("screen-reader-text", !this.checked)
})
var post_type_archives = $("#posttypearchives")
$("#relevanssi_index_post_type_archives").click(function () {
post_type_archives.toggleClass("screen-reader-text", !this.checked)
})
var fields_content = $("#index_field_input")
var fields_select = $("#relevanssi_index_fields_select")
fields_select.change(function () {
if (this.value == "some") fields_content.show()
if (this.value != "some") fields_content.hide()
})
var index_images = $("#row_index_image_files")
var index_attachments = $("#relevanssi_index_type_attachment")
index_attachments.click(function () {
if (this.checked) index_images.show()
if (!this.checked) index_images.hide()
})
$("#show_advanced_indexing").click(function (e) {
$("#advanced_indexing").toggleClass("screen-reader-text")
$("#hide_advanced_indexing").show()
$("#show_advanced_indexing").hide()
})
$("#hide_advanced_indexing").click(function (e) {
$("#advanced_indexing").toggleClass("screen-reader-text")
$("#show_advanced_indexing").show()
$("#hide_advanced_indexing").hide()
})
$("#indexing_tab :input").change(function (e) {
$("#build_index").attr("disabled", "disabled")
var relevanssi_note = $("#relevanssi-note")
relevanssi_note.show()
relevanssi_note.html('<p class="description important">' + relevanssi.options_changed + '</p>')
})
$("#relevanssi_default_orderby").change(function (e) {
if (this.value == "post_date") {
$("#relevanssi_throttle").prop("checked", false)
}
$("#throttle_disabled").toggleClass("screen-reader-text")
$("#throttle_enabled").toggleClass("screen-reader-text")
})
$("#relevanssi_show_pdf_errors").click(function (e) {
var error_box = $("#relevanssi_pdf_errors")
error_box.toggle()
var data = {
action: "relevanssi_get_pdf_errors",
}
jQuery.post(ajaxurl, data, function (response) {
error_box.val(JSON.parse(response))
})
})
$("#relevanssi_excerpts").click(function () {
$("#relevanssi_breakdown").toggleClass("relevanssi_disabled", !this.checked)
$("#relevanssi_highlighting").toggleClass(
"relevanssi_disabled",
!this.checked
)
$("#tr_excerpt_custom_fields").toggleClass(
"relevanssi_disabled",
!this.checked
)
$("#tr_excerpt_allowable_tags").toggleClass(
"relevanssi_disabled",
!this.checked
)
$("#tr_excerpt_length").toggleClass("relevanssi_disabled", !this.checked)
$("#tr_max_excerpts").toggleClass("relevanssi_disabled", !this.checked)
$("#relevanssi_excerpt_length").attr("disabled", !this.checked)
$("#relevanssi_excerpt_type").attr("disabled", !this.checked)
$("#relevanssi_max_excerpts").attr("disabled", !this.checked)
$("#relevanssi_excerpt_allowable_tags").attr("disabled", !this.checked)
$("#relevanssi_excerpt_custom_fields").attr("disabled", !this.checked)
$("#relevanssi_highlight").attr("disabled", !this.checked)
$("#relevanssi_txt_col").attr("disabled", !this.checked)
$("#relevanssi_bg_col").attr("disabled", !this.checked)
$("#relevanssi_css").attr("disabled", !this.checked)
$("#relevanssi_class").attr("disabled", !this.checked)
$("#relevanssi_hilite_title").attr("disabled", !this.checked)
$("#relevanssi_highlight_docs").attr("disabled", !this.checked)
$("#relevanssi_highlight_comments").attr("disabled", !this.checked)
$("#relevanssi_show_matches").attr("disabled", !this.checked)
$("#relevanssi_show_matches_text").attr("disabled", !this.checked)
$("#relevanssi_expand_highlights").attr("disabled", !this.checked)
})
$("#relevanssi_searchblogs_all").click(function () {
$("#relevanssi_searchblogs").attr("disabled", this.checked)
})
var min_word_length = $("#relevanssi_min_word_length")
min_word_length.change(function(e) {
if ( min_word_length.val() < 1 ) {
min_word_length.val(1)
}
if ( min_word_length.val() > 9 ) {
min_word_length.val(9)
}
})
})
var time = 0
var intervalID = 0
function relevanssiUpdateClock() {
time++
var time_formatted = rlv_format_time(Math.round(time))
document.getElementById("relevanssi_elapsed").innerHTML = time_formatted
}
jQuery(document).ready(function ($) {
$("#continue_indexing").click(function () {
$("#relevanssi-progress").show()
$("#results").show()
$("#relevanssi-timer").show()
$("#stateoftheindex").html(relevanssi.reload_state)
$("#indexing_button_instructions").hide()
var results = document.getElementById("results")
results.value = ""
intervalID = window.setInterval(relevanssiUpdateClock, 1000)
var data = {
action: "relevanssi_count_missing_posts",
}
console.log("Counting posts.")
results.value += relevanssi.counting_posts + " "
jQuery.post(ajaxurl, data, function (response) {
count_response = JSON.parse(response)
console.log("Counted " + count_response + " posts.")
results.value += count_response + " " + relevanssi.posts_found + "\n"
if (count_response > 0) {
var args = {
completed: 0,
total: count_response,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: true,
security: nonce.indexing_nonce,
}
process_indexing_step(args)
} else {
clearInterval(intervalID)
}
})
})
})
function process_indexing_step(args) {
// console.log(args.completed + " / " + args.total);
var t0 = performance.now()
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_index_posts",
completed: args.completed,
total: args.total,
offset: args.offset,
limit: args.limit,
adjust: args.adjust,
extend: args.extend,
security: args.security,
},
dataType: "json",
success: function (response) {
console.log(response)
if (response.completed == "done") {
//console.log("response " + parseInt(response.total_posts));
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
document.getElementById("relevanssi_estimated").innerHTML =
relevanssi.notimeremaining
var hidden_posts = args.total - parseInt(response.total_posts)
results_textarea.value +=
relevanssi.indexing_complete +
" " +
hidden_posts +
" " +
relevanssi.excluded_posts
results_textarea.scrollTop = results_textarea.scrollHeight
jQuery(".rpi-progress div").animate(
{
width: response.percentage + "%",
},
50,
function () {
// Animation complete.
}
)
clearInterval(intervalID)
} else {
var t1 = performance.now()
var time_seconds = (t1 - t0) / 1000
time_seconds = Math.round(time_seconds * 100) / 100
args.total_seconds += time_seconds
var estimated_time = rlv_format_approximate_time(
Math.round(
(args.total_seconds / response.percentage) * 100 -
args.total_seconds
)
)
document.getElementById(
"relevanssi_estimated"
).innerHTML = estimated_time
if (args.adjust) {
if (time_seconds < 2) {
args.limit = args.limit * 2
// current limit can be indexed in less than two seconds; double the limit
} else if (time_seconds < 5) {
args.limit += 5
// current limit can be indexed in less than five seconds; up the limit
} else if (time_seconds > 20) {
args.limit = Math.round(args.limit / 2)
if (args.limit < 1) args.limit = 1
// current limit takes more than twenty seconds; halve the limit
} else if (time_seconds > 10) {
args.limit -= 5
if (args.limit < 1) args.limit = 1
// current limit takes more than ten seconds; reduce the limit
}
}
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
results_textarea.scrollTop = results_textarea.scrollHeight
var percentage_rounded = Math.round(response.percentage)
jQuery(".rpi-progress div").animate(
{
width: percentage_rounded + "%",
},
50,
function () {
// Animation complete.
}
)
//console.log("Next step.");
var new_args = {
completed: parseInt(response.completed),
total: args.total,
offset: response.offset,
total_seconds: args.total_seconds,
limit: args.limit,
adjust: args.adjust,
extend: args.extend,
security: args.security,
}
process_indexing_step(new_args)
}
},
})
}
function rlv_format_time(total_seconds) {
var hours = Math.floor(total_seconds / 3600)
var minutes = Math.floor((total_seconds - hours * 3600) / 60)
var seconds = total_seconds - hours * 3600 - minutes * 60
if (minutes < 10) minutes = "0" + minutes
if (seconds < 10) seconds = "0" + seconds
return hours + ":" + minutes + ":" + seconds
}
function rlv_format_approximate_time(total_seconds) {
var hours = Math.floor(total_seconds / 3600)
var minutes = Math.floor(total_seconds / 60)
var seconds = total_seconds - hours * 3600 - minutes * 60
var time = ""
if (minutes > 99) {
hour_word = relevanssi.hours
if (hours == 1) hour_word = relevanssi.hour
time = relevanssi.about + " " + hours + " " + hour_word
}
if (minutes > 79 && minutes < 100) time = relevanssi.ninety_min
if (minutes > 49 && minutes < 80) time = relevanssi.sixty_min
if (minutes < 50) {
if (seconds > 30) minutes += 1
minute_word = relevanssi.minutes
if (minutes == 1) minute_word = relevanssi.minute
time = relevanssi.about + " " + minutes + " " + minute_word
}
if (minutes < 1) time = relevanssi.underminute
return time
}
jQuery(document).ready(function ($) {
$("#search").click(function (e) {
var results = document.getElementById("results")
results.innerHTML = "Searching..."
e.preventDefault()
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_admin_search",
args: document.getElementById("args").value,
posts_per_page: document.getElementById("posts_per_page").value,
post_types: document.getElementById("post_types").value,
s: document.getElementById("s").value,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
results.innerHTML = response
},
})
})
// Show the filters on the "Admin search" page.
$(document).on("click", "#show_filters", function (e) {
$("#relevanssi_filter_list").toggle()
$("#show_filters").toggle()
$("#hide_filters").toggle()
})
// Hide the filters on the "Admin search" page.
$(document).on("click", "#hide_filters", function (e) {
$("#relevanssi_filter_list").toggle()
$("#show_filters").toggle()
$("#hide_filters").toggle()
})
$(document).on("click", "#next_page", function (e) {
e.preventDefault()
var results = document.getElementById("results")
var offset = parseInt(document.getElementById("offset").innerHTML)
var posts = parseInt(document.getElementById("posts_per_page").value)
results.innerHTML = "Searching..."
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_admin_search",
args: document.getElementById("args").value,
posts_per_page: posts,
s: document.getElementById("s").value,
offset: offset,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
results.innerHTML = response
},
})
})
$(document).on("click", "#prev_page", function (e) {
e.preventDefault()
var results = document.getElementById("results")
var offset = parseInt(document.getElementById("offset").innerHTML)
var posts = parseInt(document.getElementById("posts_per_page").value)
offset = offset - posts - posts
if (offset < 0) offset = 0
results.innerHTML = "Searching..."
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_admin_search",
args: document.getElementById("args").value,
posts_per_page: document.getElementById("posts_per_page").value,
s: document.getElementById("s").value,
offset: offset,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
results.innerHTML = response
},
})
})
$(document).on("click", ".pin", function (e) {
e.preventDefault()
var keyword = e.target.dataset.keyword
var post_id = e.target.dataset.postid
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_pin_post",
keyword,
post_id,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
var results = document.getElementById("results")
results.innerHTML = "Searching..."
e.preventDefault()
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_admin_search",
args: document.getElementById("args").value,
posts_per_page: document.getElementById("posts_per_page").value,
s: document.getElementById("s").value,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
results.innerHTML = response
},
})
},
})
})
$(document).on("click", ".unpin", function (e) {
e.preventDefault()
var keyword = e.target.dataset.keyword
var post_id = e.target.dataset.postid
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_unpin_post",
keyword,
post_id,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
var results = document.getElementById("results")
results.innerHTML = "Searching..."
e.preventDefault()
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_admin_search",
args: document.getElementById("args").value,
posts_per_page: document.getElementById("posts_per_page").value,
s: document.getElementById("s").value,
security: nonce.searching_nonce,
},
dataType: "json",
success: function (response) {
results.innerHTML = response
},
})
},
})
})
})

View File

@@ -1,53 +0,0 @@
jQuery(document).ready(function ($) {
$("#build_index").click(function () {
$("#relevanssi-progress").show()
$("#results").show()
$("#relevanssi-timer").show()
$("#relevanssi-indexing-instructions").show()
$("#stateoftheindex").html(relevanssi.reload_state)
$("#indexing_button_instructions").hide()
var results = document.getElementById("results")
results.value = ""
var data = {
action: "relevanssi_truncate_index",
security: nonce.indexing_nonce,
}
intervalID = window.setInterval(relevanssiUpdateClock, 1000)
console.log("Truncating index.")
results.value += relevanssi.truncating_index + " "
jQuery.post(ajaxurl, data, function (response) {
truncate_response = JSON.parse(response)
console.log("Truncate index: " + truncate_response)
if (truncate_response == true) {
results.value += relevanssi.done + "\n"
}
var data = {
action: "relevanssi_count_posts",
}
console.log("Counting posts.")
results.value += relevanssi.counting_posts + " "
jQuery.post(ajaxurl, data, function (response) {
count_response = JSON.parse(response)
console.log("Counted " + count_response + " posts.")
var post_total = parseInt(count_response)
results.value += count_response + " " + relevanssi.posts_found + "\n"
var args = {
completed: 0,
total: post_total,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: false,
security: nonce.indexing_nonce,
}
process_indexing_step(args)
})
})
})
})

View File

@@ -1,118 +0,0 @@
p.important {
color: #992000;
}
table.form-table table.widefat th {
padding-left: 8px;
}
#relevanssi_min_word_length {
width: 3em;
}
#relevanssi_trim_logs, #relevanssi_trim_click_logs {
width: 4em;
}
#index_field_input {
margin-top: 1em;
}
#indexing_tab #results {
display: none;
width: 100%;
}
#relevanssi-progress {
display: none;
margin-bottom: 2em;
width: 100%;
height: 20px;
background-color: white;
}
.rpi-indicator {
width: 0;
height: 20px;
background-color: #afe240;
}
.relevanssi-weights-table {
min-width: 400px;
}
.relevanssi-weights-table td {
padding: 0;
}
.relevanssi-weights-table td.col-2, .relevanssi-weights-table th.col-2 {
width: 25%;
}
.rpi-progress {
display: none;
margin: 0.5em 0 2em 0;
width: 100%;
height: 20px;
background-color: white;
}
.rpi-progress div {
width: 0;
height: 20px;
background-color: #afe240;
}
#relevanssi_results {
display: none;
width: 100%;
}
#relevanssi_show_pdf_errors {
text-decoration: underline;
cursor: pointer;
color: #0073aa;
}
#relevanssi_pdf_errors {
display: none;
}
.visually_hidden {
margin: -1px;
padding: 0;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
clip: rect(0,0,0,0);
position: absolute;
}
.relevanssi_disabled, .relevanssi_disabled td, .relevanssi_disabled th, .relevanssi_disabled p {
color: #999;
}
#relevanssi-timer {
display: none;
}
#category_inclusion_checklist ul.children, #category_exclusion_checklist ul.children {
margin-left: 1.5em;
}
#relevanssi_filter_list {
display: none;
}
#redirect_table td {
vertical-align: top;
}
#relevanssi_sees_container, #relevanssi_db_view_container {
width: 80%;
background: white;
padding: 5px 20px;
border: thin solid black;
overflow: scroll;
}

View File

@@ -1,74 +0,0 @@
<?php
/**
* /lib/class-relevanssi-taxonomy-walker.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* A taxonomy walker used in Relevanssi interface.
*
* This is needed for wp_terms_checklist() in the Relevanssi admin interface to
* control the way the taxonomies are listed.
*/
class Relevanssi_Taxonomy_Walker extends Walker_Category_Checklist {
/**
* Name of the input element.
*
* @var string $name Name of the input element.
*/
public $name;
/**
* Creates a single element of the list.
*
* @see Walker::start_el()
*
* @param string $output Used to append additional content (passed by reference).
* @param object $category Category data object.
* @param int $depth Optional. Depth of category in reference to parents. Default 0.
* @param array $args Optional. An array of arguments. See wp_list_categories(). Default empty array.
* @param int $id Optional. ID of the current category. Default 0.
*/
public function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
if ( empty( $args['taxonomy'] ) ) {
$taxonomy = 'category';
} else {
$taxonomy = $args['taxonomy'];
}
$name = $this->name;
if ( ! isset( $args['popular_cats'] ) ) {
$args['popular_cats'] = array();
}
if ( ! isset( $args['selected_cats'] ) ) {
$args['selected_cats'] = array();
}
$class = '';
$inner_class = '';
if ( ! empty( $args['list_only'] ) ) {
$aria_checked = 'false';
$inner_class = 'category';
$output .= "\n" . '<li' . $class . '>' .
'<div class="' . $inner_class . '" data-term-id=' . $category->term_id .
' tabindex="0" role="checkbox" aria-checked="' . $aria_checked . '">' .
/** This filter is documented in wp-includes/category-template.php */
esc_html( apply_filters( 'the_category', $category->name, '', '' ) ) . '</div>';
} else {
$output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" .
'<label class="selectit"><input value="' . $category->term_id . '" type="checkbox" name="' . $name . '[]" id="in-' . $taxonomy . '-' . $category->term_id . '"' .
checked( in_array( intval( $category->term_id ), $args['selected_cats'], true ), true, false ) .
disabled( empty( $args['disabled'] ), false, false ) . ' /> ' .
/** This filter is documented in wp-includes/category-template.php */
esc_html( apply_filters( 'the_category', $category->name, '', '' ) ) . '</label>';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,278 +0,0 @@
<?php
/**
* /lib/compatibility/acf.php
*
* Advanced Custom Fields compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'acf/render_field_settings', 'relevanssi_acf_exclude_setting' );
add_filter( 'relevanssi_search_ok', 'relevanssi_acf_relationship_fields' );
add_filter( 'relevanssi_index_custom_fields', 'relevanssi_acf_exclude_fields', 10, 2 );
/**
* Disables Relevanssi in the ACF Relationship field post search.
*
* We don't want to use Relevanssi on the ACF Relationship field post searches, so
* this function disables it (on the 'relevanssi_search_ok' hook).
*
* @param boolean $search_ok Block the search or not.
*
* @return boolean False, if this is an ACF Relationship field search, pass the
* parameter unchanged otherwise.
*/
function relevanssi_acf_relationship_fields( $search_ok ) {
if ( isset( $_REQUEST['action'] ) && 'acf' === substr( $_REQUEST['action'], 0, 3 ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$search_ok = false;
}
return $search_ok;
}
/**
* Indexes the human-readable value of "choice" options list from ACF.
*
* @author Droz Raphaël
*
* @param array $insert_data The insert data array.
* @param int $post_id The post ID.
* @param string $field_name Name of the field.
* @param string $field_value The field value.
*
* @return int Number of tokens indexed.
*/
function relevanssi_index_acf( &$insert_data, $post_id, $field_name, $field_value ) {
if ( ! is_admin() ) {
include_once ABSPATH . 'wp-admin/includes/plugin.php'; // Otherwise is_plugin_active() will cause a fatal error.
}
if ( ! function_exists( 'is_plugin_active' ) ) {
return 0;
}
if ( ! is_plugin_active( 'advanced-custom-fields/acf.php' ) && ! is_plugin_active( 'advanced-custom-fields-pro/acf.php' ) ) {
return 0;
}
if ( ! function_exists( 'get_field_object' ) ) {
return 0; // ACF is active, but not loaded.
}
$field_object = get_field_object( $field_name, $post_id );
if ( ! isset( $field_object['choices'] ) ) {
return 0; // Not a "select" field.
}
if ( is_array( $field_value ) ) {
return 0; // Not handled (currently).
}
if ( ! isset( $field_object['choices'][ $field_value ] ) ) {
return 0; // Value does not exist.
}
$n = 0;
/**
* Filters the field value before it is used to save the insert data.
*
* The value is used as an array key, so it needs to be an integer or a
* string. If your custom field values are arrays or objects, use this
* filter hook to convert them into strings.
*
* @param mixed $field_content The ACF field value.
* @param string $field_name The ACF field name.
* @param int $post_id The post ID.
*
* @return string|int The field value.
*/
$value = apply_filters(
'relevanssi_acf_field_value',
$field_object['choices'][ $field_value ],
$field_name,
$post_id
);
if ( $value && ( is_integer( $value ) || is_string( $value ) ) ) {
$min_word_length = get_option( 'relevanssi_min_word_length', 3 );
/** This filter is documented in lib/indexing.php */
$value_tokens = apply_filters( 'relevanssi_indexing_tokens', relevanssi_tokenize( $value, true, $min_word_length, 'indexing' ), 'custom_field' );
foreach ( $value_tokens as $token => $count ) {
$n++;
if ( ! isset( $insert_data[ $token ]['customfield'] ) ) {
$insert_data[ $token ]['customfield'] = 0;
}
$insert_data[ $token ]['customfield'] += $count;
// Premium indexes more detail about custom fields.
if ( function_exists( 'relevanssi_customfield_detail' ) ) {
$insert_data = relevanssi_customfield_detail( $insert_data, $token, $count, $field_name );
}
}
}
return $n;
}
/**
* Adds a Relevanssi exclude setting to ACF fields.
*
* @param array $field The field object array.
*/
function relevanssi_acf_exclude_setting( $field ) {
if ( ! function_exists( 'acf_render_field_setting' ) ) {
return;
}
if ( 'clone' === $field['type'] ) {
return;
}
acf_render_field_setting(
$field,
array(
'label' => __( 'Exclude from Relevanssi index', 'relevanssi' ),
'instructions' => __( 'If this setting is enabled, Relevanssi will not index the value of this field for posts.', 'relevanssi' ),
'name' => 'relevanssi_exclude',
'type' => 'true_false',
'ui' => 1,
),
true
);
}
/**
* Excludes ACF fields based on the exclude setting.
*
* Hooks on to relevanssi_index_custom_fields.
*
* @param array $fields The list of custom fields to index.
* @param int $post_id The post ID.
*
* @return array Filtered list of custom fields.
*/
function relevanssi_acf_exclude_fields( $fields, $post_id ) {
$included_fields = array();
$excluded_fields = array();
/**
* Filters the types of ACF fields to exclude from indexing.
*
* By default, blocks 'repeater', 'flexible_content' and 'group' are
* excluded from Relevanssi indexing. You can add other field types here.
*
* @param array $excluded_field_types The field types to exclude.
*/
$blocked_field_types = apply_filters(
'relevanssi_blocked_field_types',
array( 'repeater', 'flexible_content', 'group' )
);
foreach ( $fields as $field ) {
$field_object = get_field_object( $field );
if ( ! $field_object || ! is_array( $field_object ) ) {
$field_id = relevanssi_acf_get_field_id( $field, $post_id );
if ( ! $field_id ) {
// No field ID -> not an ACF field. Include.
$included_fields[] = $field;
} else {
/*
* This field has a field ID, but get_field_object() does not
* return a field object. This may be a clone field, in which
* case we can try to get the field object from the field ID.
* Clone fields have keys like field_xxx_field_yyy, where the
* field_yyy is the part we need.
*/
$field_id = preg_replace( '/.*_(field_.*)/', '$1', $field_id );
$field_object = get_field_object( $field_id );
}
}
if ( $field_object ) {
/**
* Filters the ACF field object.
*
* If the filter returns a false value, Relevanssi will not index
* the field.
*
* @param array $field_object The field object.
* @param int $post_id The post ID.
*
* @return array The filtered field object.
*/
$field_object = apply_filters(
'relevanssi_acf_field_object',
$field_object,
$post_id
);
if ( ! $field_object ) {
continue;
}
if ( isset( $field_object['relevanssi_exclude'] ) && 1 === $field_object['relevanssi_exclude'] ) {
continue;
}
if ( relevanssi_acf_is_parent_excluded( $field_object ) ) {
continue;
}
if ( isset( $field_object['type'] ) && in_array( $field_object['type'], $blocked_field_types, true ) ) {
continue;
}
$included_fields[] = $field;
}
}
return $included_fields;
}
/**
* Checks if the field has an excluded parent field.
*
* If the field has a "parent" value set, this function gets the parent field
* post based on the post ID in the "parent" value. This is done recursively
* until we reach the top or find an excluded parent.
*
* @param array $field_object The field object.
*
* @return bool Returns true if the post has an excluded parent.
*/
function relevanssi_acf_is_parent_excluded( $field_object ) {
if ( isset( $field_object['parent'] ) ) {
$parent = $field_object['parent'];
if ( $parent ) {
$parent_field_post = get_post( $parent );
if ( $parent_field_post ) {
$parent_object = get_field_object( $parent_field_post->post_name );
if ( $parent_object ) {
if ( isset( $parent_object['relevanssi_exclude'] ) && 1 === $parent_object['relevanssi_exclude'] ) {
return true;
}
return relevanssi_acf_is_parent_excluded( $parent_object );
}
}
}
}
return false;
}
/**
* Gets the field ID from the field name.
*
* The field ID is stored in the postmeta table with the field name prefixed
* with an underscore as the key.
*
* @param string $field_name The field name.
* @param int $post_id The post ID.
*
* @return string The field ID.
*/
function relevanssi_acf_get_field_id( $field_name, $post_id ) {
global $wpdb;
$field_id = $wpdb->get_var(
$wpdb->prepare(
"SELECT meta_value FROM $wpdb->postmeta
WHERE post_id = %d
AND meta_key = %s",
$post_id,
'_' . $field_name
)
);
return $field_id;
}

View File

@@ -1,108 +0,0 @@
<?php
/**
* /lib/compatibility/aioseo.php
*
* All-in-One SEO noindex filtering function.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_do_not_index', 'relevanssi_aioseo_noindex', 10, 2 );
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_aioseo_exclude' );
add_action( 'relevanssi_indexing_tab_advanced', 'relevanssi_aioseo_form', 20 );
add_action( 'relevanssi_indexing_options', 'relevanssi_aioseo_options' );
/**
* Blocks indexing of posts marked "noindex" in the All-in-One SEO settings.
*
* Attaches to the 'relevanssi_do_not_index' filter hook.
*
* @param boolean $do_not_index True, if the post shouldn't be indexed.
* @param integer $post_id The post ID number.
*
* @return string|boolean If the post shouldn't be indexed, this returns
* 'aioseo_seo'. The value may also be a boolean.
*/
function relevanssi_aioseo_noindex( bool $do_not_index, int $post_id ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $do_not_index;
}
$noindex_posts = relevanssi_aioseo_get_noindex_posts();
if ( in_array( $post_id, $noindex_posts, true ) ) {
$do_not_index = 'All-in-One SEO';
}
return $do_not_index;
}
/**
* Excludes the "noindex" posts from Relevanssi indexing.
*
* Adds a MySQL query restriction that blocks posts that have the aioseo SEO
* "noindex" setting set to "1" from indexing.
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_aioseo_exclude( array $restriction ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $restriction;
}
global $wpdb;
$restriction['mysql'] .= " AND post.ID NOT IN (SELECT post_id FROM
{$wpdb->prefix}aioseo_posts WHERE robots_noindex = '1' ) ";
$restriction['reason'] .= ' All-in-One SEO';
return $restriction;
}
/**
* Fetches the post IDs where robots_noindex is set to 1 in the aioseo_posts
* table.
*
* @return array An array of post IDs.
*/
function relevanssi_aioseo_get_noindex_posts() {
global $wpdb, $relevanssi_aioseo_noindex_cache;
if ( ! empty( $relevanssi_aioseo_noindex_cache ) ) {
return $relevanssi_aioseo_noindex_cache;
}
$relevanssi_aioseo_noindex_cache = $wpdb->get_col( "SELECT post_id FROM {$wpdb->prefix}aioseo_posts WHERE 'robots_noindex' = '1'" );
return $relevanssi_aioseo_noindex_cache;
}
/**
* Prints out the form fields for disabling the feature.
*/
function relevanssi_aioseo_form() {
$seo_noindex = get_option( 'relevanssi_seo_noindex' );
$seo_noindex = relevanssi_check( $seo_noindex );
?>
<tr>
<th scope="row">
<label for='relevanssi_seo_noindex'><?php esc_html_e( 'Use All-in-One SEO noindex', 'relevanssi' ); ?></label>
</th>
<td>
<label for='relevanssi_seo_noindex'>
<input type='checkbox' name='relevanssi_seo_noindex' id='relevanssi_seo_noindex' <?php echo esc_attr( $seo_noindex ); ?> />
<?php esc_html_e( 'Use All-in-One SEO noindex.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will not index posts marked as "No index" in All-in-One SEO settings.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
}
/**
* Saves the SEO No index option.
*
* @param array $request An array of option values from the request.
*/
function relevanssi_aioseo_options( array $request ) {
relevanssi_update_off_or_on( $request, 'relevanssi_seo_noindex', true );
}

View File

@@ -1,19 +0,0 @@
<?php
/**
* /lib/compatibility/avada.php
*
* Avada theme compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter(
'fusion_live_search_query_args',
function( $args ) {
$args['relevanssi'] = true;
return $args;
}
);

View File

@@ -1,98 +0,0 @@
<?php
/**
* /lib/compatibility/bricks.php
*
* Bricks theme compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'bricks/posts/query_vars', 'relevanssi_bricks_enable', 10 );
add_filter( 'relevanssi_custom_field_value', 'relevanssi_bricks_values', 10, 3 );
add_filter( 'relevanssi_index_custom_fields', 'relevanssi_add_bricks' );
add_filter( 'option_relevanssi_index_fields', 'relevanssi_bricks_fix_none_setting' );
add_action( 'save_post', 'relevanssi_insert_edit', 99, 1 );
/**
* Enables Relevanssi in the query when the 's' query var is set.
*
* @param array $query_vars The query variables.
*
* @return array The query variables with the Relevanssi toggle enabled.
*/
function relevanssi_bricks_enable( $query_vars ) {
if ( isset( $query_vars['s'] ) ) {
$query_vars['relevanssi'] = true;
}
return $query_vars;
}
/**
* Adds the `_bricks_page_content_2` to the list of indexed custom fields.
*
* @param array|boolean $fields An array of custom fields to index, or false.
*
* @return array An array of custom fields, including `_bricks_page_content_2`.
*/
function relevanssi_add_bricks( $fields ) {
if ( ! is_array( $fields ) ) {
$fields = array();
}
if ( ! in_array( '_bricks_page_content_2', $fields, true ) ) {
$fields[] = '_bricks_page_content_2';
}
return $fields;
}
/**
* Includes only text from _bricks_page_content_2 custom field.
*
* This function goes through the multilevel array of _bricks_page_content_2
* and only picks up the "text" elements inside it, discarding everything else.
*
* @param array $value An array of custom field values.
* @param string $field The name of the custom field.
* @param int $post_id The post ID.
*
* @return array An array containing a string with all the values concatenated
* together.
*/
function relevanssi_bricks_values( $value, $field, $post_id ) {
if ( '_bricks_page_content_2' !== $field ) {
return $value;
}
$content = '';
array_walk_recursive(
$value,
function( $text, $key ) use ( &$content ) {
if ( 'text' === $key ) {
$content .= ' ' . $text;
}
}
);
return array( $content );
}
/**
* Makes sure the Bricks builder shortcode is included in the index, even when
* the custom field setting is set to 'none'.
*
* @param string $value The custom field indexing setting value. The parameter
* is ignored, Relevanssi disables this filter and then checks the option to
* see what the value is.
*
* @return string If value is undefined, it's set to '_bricks_page_content_2'.
*/
function relevanssi_bricks_fix_none_setting( $value ) {
if ( ! $value ) {
$value = '_bricks_page_content_2';
}
return $value;
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* /lib/compatibility/elementor.php
*
* Elementor page builder compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_search_ok', 'relevanssi_block_elementor_library', 10, 2 );
/**
* Blocks Relevanssi from interfering with the Elementor Library searches.
*
* @param bool $ok Should Relevanssi be allowed to process the query.
* @param WP_Query $query The WP_Query object.
*
* @return bool Returns false, if this is an Elementor library search.
*/
function relevanssi_block_elementor_library( bool $ok, WP_Query $query ) : bool {
if ( 'elementor_library' === $query->query_vars['post_type'] ) {
$ok = false;
}
return $ok;
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* /lib/compatibility/fibosearch.php
*
* Fibo Search compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'dgwt/wcas/search_query/args', 'relevanssi_enable_relevanssi_in_fibo' );
/**
* Adds the 'relevanssi' parameter to the Fibo Search.
*
* Uses the dgwt/wcas/search_query_args filter hook to modify the search query.
*
* @params array $args The search arguments.
*
* @return array
*/
function relevanssi_enable_relevanssi_in_fibo( $args ) {
$args['relevanssi'] = true;
return $args;
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* /lib/compatibility/groups.php
*
* Groups compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_groups_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* Only applies to published posts.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_groups_compatibility( $post_ok, $post_id ) {
$status = relevanssi_get_post_status( $post_id );
if ( 'publish' === $status ) {
// Only apply to published posts, don't apply to drafts.
$current_user = wp_get_current_user();
$post_ok = Groups_Post_Access::user_can_read_post( $post_id, $current_user->ID );
}
return $post_ok;
}

View File

@@ -1,174 +0,0 @@
<?php
/**
* /lib/compatibility/gutenberg.php
*
* Gutenberg compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_content', 'relevanssi_gutenberg_block_rendering', 10, 2 );
/**
* Registers rest_after_insert_{post_type} actions for all indexed post types.
*
* Runs on `admin_init` action hook and registers the function
* `relevanssi_save_gutenberg_postdata` for all indexed post types.
*
* @see relevanssi_save_gutenberg_postdata
*/
function relevanssi_register_gutenberg_actions() {
if ( ! RELEVANSSI_PREMIUM ) {
return;
}
$index_post_types = get_option( 'relevanssi_index_post_types', array() );
array_walk(
$index_post_types,
function ( $post_type ) {
if ( 'bogus' !== $post_type ) {
add_action(
'rest_after_insert_' . $post_type,
'relevanssi_save_gutenberg_postdata'
);
}
}
);
}
/**
* Renders Gutenberg blocks.
*
* Renders all sorts of Gutenberg blocks, including reusable blocks and ACF
* blocks. Also enables basic Gutenberg deindexing: you can add an extra CSS
* class 'relevanssi_noindex' to a block to stop it from being indexed by
* Relevanssi. This function is essentially the same as core do_blocks().
*
* @see do_blocks()
*
* @param string $content The post content.
* @param object $post_object The post object.
*
* @return string The post content with the rendered content added.
*/
function relevanssi_gutenberg_block_rendering( $content, $post_object ) {
/**
* Filters whether the blocks are rendered or not.
*
* If this filter returns false, the blocks in this post are not rendered,
* and the post content is returned as such.
*
* @param boolean If true, render the blocks. Default true.
* @param object The post object.
*/
if ( ! apply_filters( 'relevanssi_render_blocks', true, $post_object ) ) {
return $content;
}
$blocks = parse_blocks( $content );
$output = '';
foreach ( $blocks as $block ) {
/**
* Filters the Gutenberg block before it is rendered.
*
* If the block is non-empty after the filter and it's className
* parameter is not 'relevanssi_noindex', it will be passed on to the
* render_block() function for rendering.
*
* @see render_block
*
* @param array $block The Gutenberg block element.
*/
$block = apply_filters( 'relevanssi_block_to_render', $block );
if ( ! $block ) {
continue;
}
if (
isset( $block['attrs']['className'] )
&& false !== strstr( $block['attrs']['className'], 'relevanssi_noindex' )
) {
continue;
}
$block = relevanssi_process_inner_blocks( $block );
/**
* Filters the Gutenberg block after it is rendered.
*
* The value is the output from render_block( $block ). Feel free to
* modify it as you wish.
*
* @see render_block
*
* @param string The rendered block content.
* @param array $block The Gutenberg block being rendered.
*
* @return string The filtered block content.
*/
$output .= apply_filters( 'relevanssi_rendered_block', render_block( $block ), $block );
}
// If there are blocks in this content, we shouldn't run wpautop() on it later.
$priority = has_filter( 'the_content', 'wpautop' );
if ( false !== $priority && doing_filter( 'the_content' ) && has_blocks( $content ) ) {
remove_filter( 'the_content', 'wpautop', $priority );
add_filter( 'the_content', '_restore_wpautop_hook', $priority + 1 );
}
return $output;
}
/**
* Runs recursively through inner blocks to filter them.
*
* Runs relevanssi_block_to_render and the relevanssi_noindex CSS class check
* on all inner blocks. If inner blocks are filtered out, they will be removed
* with empty blocks of the type "core/fake". Removing the inner blocks causes
* problems; that's why they are replaced. The blocks are rendered here;
* everything will be rendered once at the top level.
*
* @param array $block A Gutenberg block.
*
* @return array The filtered block.
*/
function relevanssi_process_inner_blocks( $block ) {
$innerblocks_to_keep = array();
$empty_block = array(
'blockName' => 'core/fake',
'attrs' => array(),
'innerHTML' => '',
'innerBlocks' => array(),
);
foreach ( $block['innerBlocks'] as $inner_block ) {
/* Filter documented in /lib/compatibility/gutenberg.php. */
$inner_block = apply_filters( 'relevanssi_block_to_render', $inner_block );
if ( ! $inner_block ) {
$innerblocks_to_keep[] = $empty_block;
continue;
}
if (
isset( $inner_block['attrs']['className'] )
&& false !== strstr( $inner_block['attrs']['className'], 'relevanssi_noindex' )
) {
$innerblocks_to_keep[] = $empty_block;
continue;
}
$inner_block = relevanssi_process_inner_blocks( $inner_block );
$innerblocks_to_keep[] = $inner_block;
}
$block['innerBlocks'] = $innerblocks_to_keep;
return $block;
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* /lib/compatibility/jetsmartfilters.php
*
* JetSmartFilters compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'pre_get_posts', 'relevanssi_jetsmartfilters', 9999 );
/**
* Makes JetSmartFilters use posts from Relevanssi.
*
* @param WP_Query $wp_query The wp_query object.
*/
function relevanssi_jetsmartfilters( $wp_query ) {
if (
! isset( $wp_query->query['jet_smart_filters'] )
|| empty( $wp_query->query['s'] )
) {
return;
}
$args = array(
's' => $wp_query->query['s'],
'fields' => 'ids',
'posts_per_page' => -1,
'relevanssi' => true,
);
$relevanssi_query = new WP_Query( $args );
$results = ! empty( $relevanssi_query->posts )
? $relevanssi_query->posts
: array( 0 );
$wp_query->set( 'post__in', $results );
$wp_query->set( 'post_type', 'any' );
$wp_query->set( 'post_status', 'any' );
$wp_query->set( 'orderby', 'post__in' );
$wp_query->set( 'order', 'DESC' );
$wp_query->set( 's', false );
}

View File

@@ -1,31 +0,0 @@
<?php
/**
* /lib/compatibility/memberpress.php
*
* Memberpress compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_memberpress_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_memberpress_compatibility( $post_ok, $post_id ) {
$post = get_post( $post_id );
if ( MeprRule::is_locked( $post ) ) {
$post_ok = false;
}
return $post_ok;
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* /lib/compatibility/members.php
*
* Members compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_members_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* Only applies to private posts and only if the "content permissions" feature
* is enabled.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_members_compatibility( $post_ok, $post_id ) {
$status = relevanssi_get_post_status( $post_id );
if ( 'private' === $status ) {
if ( members_content_permissions_enabled() ) {
$post_ok = members_can_current_user_view_post( $post_id );
}
}
return $post_ok;
}

View File

@@ -1,94 +0,0 @@
<?php
/**
* /lib/compatibility/ninjatables.php
*
* Ninja Tables compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_content', 'relevanssi_index_ninja_tables' );
/**
* Indexes Ninja Tables table contents.
*
* Uses regular expression matching to find all the Ninja Tables shortcodes in
* the post content and then uses relevanssi_index_ninja_table() to convert the
* tables into strings.
*
* @uses $wpdb WordPress database abstraction.
* @see relevanssi_index_ninja_table()
*
* @param string $content The post content.
*
* @return string Post content with the Ninja Tables data.
*/
function relevanssi_index_ninja_tables( $content ) {
$m = preg_match_all(
'/.*\[ninja_tables.*?id=["\'](\d+)["\'].*?\]/im',
$content,
$matches,
PREG_PATTERN_ORDER
);
if ( ! $m ) {
return $content;
}
foreach ( $matches[1] as $table_id ) {
$content .= ' ' . relevanssi_index_ninja_table( $table_id );
}
return $content;
}
/**
* Creates a string containing a Ninja Table table contents.
*
* The string contains the caption and the values from each row. The table
* title and description are also included, if they are set visible on the
* frontend.
*
* @uses $wpdb WordPress database abstraction.
*
* @param int $table_id The table ID.
*
* @return string The table content as a string.
*/
function relevanssi_index_ninja_table( $table_id ) {
global $wpdb;
$table_post = get_post( $table_id );
$table_settings = get_post_meta( $table_id, '_ninja_table_settings', true );
$table_contents = '';
if ( isset( $table_settings['show_description'] ) && '1' === $table_settings['show_description'] ) {
$table_contents .= ' ' . $table_post->post_content;
}
if ( isset( $table_settings['show_title'] ) && '1' === $table_settings['show_title'] ) {
$table_contents .= ' ' . $table_post->post_title;
}
$table_contents .= ' ' . get_post_meta( $table_id, '_ninja_table_caption', true );
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT value FROM {$wpdb->prefix}ninja_table_items WHERE table_id=%d",
$table_id
)
);
foreach ( $rows as $row ) {
$array_values = array_map(
function( $value ) {
if ( is_object( $value ) ) {
return '';
}
return strval( $value );
},
array_values( get_object_vars( json_decode( $row->value ) ) )
);
$table_contents .= ' ' . implode( ' ', $array_values );
}
return $table_contents;
}

View File

@@ -1,259 +0,0 @@
<?php
/**
* /lib/compatibility/oxygen.php
*
* Oxygen Builder compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_custom_field_value', 'relevanssi_oxygen_compatibility', 10, 3 );
add_filter( 'relevanssi_index_custom_fields', 'relevanssi_add_oxygen' );
add_filter( 'option_relevanssi_index_fields', 'relevanssi_oxygen_fix_none_setting' );
add_filter( 'relevanssi_oxygen_section_content', 'relevanssi_oxygen_code_block' );
add_filter( 'relevanssi_oxygen_section_content', 'relevanssi_oxygen_rich_text' );
add_action( 'save_post', 'relevanssi_insert_edit', 99, 1 );
/**
* Cleans up the Oxygen Builder custom field for Relevanssi consumption.
*
* Splits up the big custom field content from ct_builder_shortcodes into
* sections ([ct_section] tags). Each section can be processed with filters
* defined with `relevanssi_oxygen_section_filters`, for example to remove
* sections based on their "nicename" or "ct_category" values. After that the
* section is passed through the `relevanssi_oxygen_section_content` filter.
* Finally all shortcode tags are removed, leaving just the content.
*
* @param array $value An array of custom field values.
* @param string $field The name of the custom field. This function only looks
* at `ct_builder_shortcodes` fields.
* @param int $post_id The post ID.
*
* @return array|null An array of custom field values, null if no value exists.
*/
function relevanssi_oxygen_compatibility( $value, $field, $post_id ) {
if ( 'ct_builder_json' === $field ) {
$json = array();
foreach ( $value as $row ) {
$json[] = json_decode( $row );
}
$content = '';
if ( isset( $json[0]->children ) ) {
foreach ( $json[0]->children as $child ) {
$content .= relevanssi_process_oxygen_child( $child );
}
}
$value[0] = $content;
return $value;
}
if ( 'ct_builder_shortcodes_revisions_dates' === $field ) {
return '';
}
if ( 'ct_builder_shortcodes_revisions' === $field ) {
return '';
}
if ( 'ct_builder_shortcodes' === $field ) {
if ( version_compare( CT_VERSION, '4.0', '>=' ) ) {
return null;
}
if ( empty( $value ) ) {
return null;
}
$content_tags = explode( '[ct_section', $value[0] );
$page_content = '';
foreach ( $content_tags as $content ) {
if ( empty( $content ) ) {
continue;
}
if ( '[' !== substr( $content, 0, 1 ) ) {
$content = '[ct_section' . $content;
}
/**
* Allows defining filters to remove Oxygen Builder sections.
*
* The filters are arrays, with the array key defining the key and
* the value defining the value. If the filter array is
* array( 'nicename' => 'Hero BG' ), Relevanssi will look for
* sections that have "nicename":"Hero BG" in their settings and
* will remove those.
*
* @param array An array of filtering rules, defaults empty.
*
* @return array
*/
$filters = apply_filters(
'relevanssi_oxygen_section_filters',
array()
);
array_walk(
$filters,
function( $filter ) use ( &$content ) {
foreach ( $filter as $key => $value ) {
if ( stristr( $content, '"' . $key . '":"' . $value . '"' ) !== false ) {
$content = '';
}
}
}
);
$content = preg_replace(
array(
'/\[oxygen.*?\]/',
'/\[\/?ct_.*?\]/',
'/\[\/?oxy_.*?\]/',
),
' ',
/**
* Filters the Oxygen Builder section content before the
* Oxygen Builder shortcode tags are removed.
*
* @param string $content The single section content.
* @param int $post_id The post ID.
*
* @return string
*/
apply_filters(
'relevanssi_oxygen_section_content',
$content,
$post_id
)
);
$page_content .= $content;
}
$page_content = relevanssi_do_shortcode( $page_content );
$value[0] = $page_content;
}
return $value;
}
/**
* Recursively processes the Oxygen JSON data.
*
* This function extracts all the ct_content data from the JSON. All elements
* are run through the relevanssi_oxygen_element filter hook. You can use that
* filter hook to modify or to eliminate elements from the JSON.
*
* @param array $child The child element array.
*
* @return string The content from the child and the grandchildren.
*/
function relevanssi_process_oxygen_child( $child ) : string {
/**
* Filters the Oxygen JSON child element.
*
* If the filter returns an empty value, the child element and all its
* children will be ignored.
*
* @param array $child The JSON child element.
*/
$child = apply_filters( 'relevanssi_oxygen_element', $child );
if ( empty( $child ) ) {
return '';
}
$child_content = ' ';
if ( isset( $child->options->ct_content ) ) {
$child_content .= $child->options->ct_content;
}
if ( isset( $child->options->original->{'code-php'} ) ) {
// For code and HTML blocks, strip all tags.
$child_content .= wp_strip_all_tags( $child->options->original->{'code-php'} );
}
if ( isset( $child->children ) ) {
foreach ( $child->children as $grandchild ) {
$child_content .= relevanssi_process_oxygen_child( $grandchild );
}
}
return $child_content;
}
/**
* Adds the Oxygen custom field to the list of indexed custom fields.
*
* @param array|boolean $fields An array of custom fields to index, or false.
*
* @return array An array of custom fields, including `ct_builder_json` or
* `ct_builder_shortcodes`.
*/
function relevanssi_add_oxygen( $fields ) {
$oxygen_field = version_compare( CT_VERSION, '4.0', '>=' )
? 'ct_builder_json'
: 'ct_builder_shortcodes';
if ( ! is_array( $fields ) ) {
$fields = array();
}
if ( ! in_array( $oxygen_field, $fields, true ) ) {
$fields[] = $oxygen_field;
}
return $fields;
}
/**
* Makes sure the Oxygen builder shortcode is included in the index, even when
* the custom field setting is set to 'none'.
*
* @param string $value The custom field indexing setting value. The parameter
* is ignored, Relevanssi disables this filter and then checks the option to
* see what the value is.
*
* @return string If value is undefined, it's set to 'ct_builder_json' or
* 'ct_builder_shortcodes'.
*/
function relevanssi_oxygen_fix_none_setting( $value ) {
if ( ! $value ) {
$value = version_compare( CT_VERSION, '4.0', '>=' )
? 'ct_builder_json'
: 'ct_builder_shortcodes';
}
return $value;
}
/**
* Indexes the Base64 encoded PHP & HTML code block contents.
*
* @param string $content The section content from the
* relevanssi_oxygen_section_content filter hook.
*
* @return string $content The content with the decoded code block content
* added to the end.
*/
function relevanssi_oxygen_code_block( $content ) {
if ( preg_match_all( '/\[ct_code_block.*?ct_code_block\]/', $content, $matches ) ) {
foreach ( $matches[0] as $match ) {
if ( preg_match_all( '/"code-php":"(.*?)"/', $match, $block_matches ) ) {
foreach ( $block_matches[1] as $encoded_text ) {
$content .= ' ' . base64_decode( $encoded_text ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
}
}
}
}
return $content;
}
/**
* Removes the Oxygen rich text shortcode.
*
* @param string $content The content of the Oxygen section.
*
* @return string The content with the oxy_rich_text shortcodes removed.
*/
function relevanssi_oxygen_rich_text( $content ) {
$content = preg_replace( '/\[\/?oxy_rich_text.*?\]/im', '', $content );
return $content;
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* /lib/compatibility/paidmembershippro.php
*
* Paid Membership Pro compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_paidmembershippro_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_paidmembershippro_compatibility( $post_ok, $post_id ) {
$pmpro_active = get_option( 'pmpro_filterqueries', 0 );
if ( $pmpro_active ) {
$status = relevanssi_get_post_status( $post_id );
if ( 'publish' === $status ) {
// Only apply to published posts, don't apply to drafts.
$current_user = wp_get_current_user();
$post_ok = pmpro_has_membership_access( $post_id, $current_user->ID );
}
}
return $post_ok;
}

View File

@@ -1,205 +0,0 @@
<?php
/**
* /lib/compatibility/polylang.php
*
* Polylang compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_modify_wp_query', 'relevanssi_polylang_filter' );
add_filter( 'relevanssi_where', 'relevanssi_polylang_where_include_terms' );
add_filter( 'relevanssi_hits_filter', 'relevanssi_polylang_term_filter' );
/**
* Removes the Polylang language filters.
*
* If the Polylang allow all option ('relevanssi_polylang_all_languages') is
* enabled this removes the Polylang language filter. By default Polylang
* filters the languages using a taxonomy query.
*
* @param object $query WP_Query object we need to clean up.
*/
function relevanssi_polylang_filter( $query ) {
$polylang_allow_all = get_option( 'relevanssi_polylang_all_languages' );
if ( 'on' === $polylang_allow_all ) {
$ok_queries = array();
if ( ! isset( $query->tax_query ) ) {
// No tax query set, backing off.
return;
}
if ( ! isset( $query->tax_query->queries ) || ! is_array( $query->tax_query->queries ) ) {
// No tax query set, backing off.
return;
}
foreach ( $query->tax_query->queries as $tax_query ) {
if ( isset( $tax_query['taxonomy'] ) && 'language' !== $tax_query['taxonomy'] ) {
// Not a language tax query.
$ok_queries[] = $tax_query;
}
}
$query->tax_query->queries = $ok_queries;
if ( isset( $query->query_vars['tax_query'] ) ) {
// Tax queries can be here as well, so let's sweep this one too.
$ok_queries = array();
foreach ( $query->query_vars['tax_query'] as $tax_query ) {
if ( isset( $tax_query['taxonomy'] ) ) {
if ( 'language' !== $tax_query['taxonomy'] ) {
$ok_queries[] = $tax_query;
}
} else {
// Relation parameter most likely.
$ok_queries[] = $tax_query;
}
}
$query->query_vars['tax_query'] = $ok_queries;
}
if ( isset( $query->query_vars['taxonomy'] ) && 'language' === $query->query_vars['taxonomy'] ) {
// Another way to set the taxonomy.
unset( $query->query_vars['taxonomy'] );
unset( $query->query_vars['term'] );
}
}
return $query;
}
/**
* Allows taxonomy terms in language-restricted searches.
*
* This is a bit of a hack, where the language taxonomy WHERE clause is modified
* on the go to allow all posts with the post ID -1 (which means taxonomy terms
* and users). This may break suddenly in updates, but I haven't come up with a
* better way so far.
*
* @param string $where The WHERE clause to modify.
*
* @return string The WHERE clause with additional filtering included.
*
* @since 2.1.6
*/
function relevanssi_polylang_where_include_terms( $where ) {
global $wpdb;
$current_language = substr( get_locale(), 0, 2 );
if ( function_exists( 'pll_current_language' ) ) {
$current_language = pll_current_language();
}
$languages = get_terms( array( 'taxonomy' => 'language' ) );
$language_id = 0;
foreach ( $languages as $language ) {
if (
! is_wp_error( $language ) &&
$language instanceof WP_Term &&
$language->slug === $current_language
) {
$language_id = intval( $language->term_id );
break;
}
}
// Language ID should now have current language ID.
if ( 0 !== $language_id ) {
// Do a simple search-and-replace to modify the query.
$where = preg_replace( '/\s+/', ' ', $where );
$where = preg_replace( '/\(\s/', '(', $where );
$where = str_replace(
"AND relevanssi.doc IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->prefix}term_relationships AS tr WHERE tr.term_taxonomy_id IN ($language_id))",
"AND (relevanssi.doc IN ( SELECT DISTINCT(tr.object_id) FROM {$wpdb->prefix}term_relationships AS tr WHERE tr.term_taxonomy_id IN ($language_id)) OR (relevanssi.doc = -1))",
$where
);
}
return $where;
}
/**
* Filters out taxonomy terms in the wrong language.
*
* If all languages are not allowed, this filter goes through the results and
* removes the taxonomy terms in the wrong language. This can't be done in the
* original query because the term language information is slightly hard to
* find.
*
* @param array $hits The found posts are in $hits[0].
*
* @return array The $hits array with the unwanted posts removed.
*
* @since 2.1.6
*/
function relevanssi_polylang_term_filter( $hits ) {
$polylang_allow_all = get_option( 'relevanssi_polylang_all_languages' );
if ( 'on' !== $polylang_allow_all ) {
$current_language = substr( get_locale(), 0, 2 );
if ( function_exists( 'pll_current_language' ) ) {
$current_language = pll_current_language();
}
$accepted_hits = array();
foreach ( $hits[0] as $hit ) {
$original_hit = $hit;
if ( is_numeric( $hit ) ) {
// In case "fields" is set to "ids", fetch the post object we need.
$original_hit = $hit;
$hit = get_post( $hit );
}
if ( ! isset( $hit->post_content ) && isset( $hit->ID ) ) {
// The "fields" is set to "id=>parent".
$original_hit = $hit;
$hit = get_post( $hit->ID );
}
if ( isset( $hit->ID ) && -1 === $hit->ID && isset( $hit->term_id ) ) {
$term_id = intval( $hit->term_id );
$translations = pll_get_term_translations( $term_id );
if (
isset( $translations[ $current_language ] ) &&
$translations[ $current_language ] === $term_id
) {
$accepted_hits[] = $original_hit;
}
} else {
$accepted_hits[] = $original_hit;
}
}
$hits[0] = $accepted_hits;
}
return $hits;
}
/**
* Returns the term_taxonomy_id matching the Polylang language based on locale.
*
* @param string $locale The locale string for the language.
*
* @return int The term_taxonomy_id for the language; 0 if nothing is found.
*/
function relevanssi_get_language_term_taxonomy_id( $locale ) {
global $wpdb, $relevanssi_language_term_ids;
if ( isset( $relevanssi_language_term_ids[ $locale ] ) ) {
return $relevanssi_language_term_ids[ $locale ];
}
$languages = $wpdb->get_results(
"SELECT term_taxonomy_id, description FROM $wpdb->term_taxonomy " .
"WHERE taxonomy = 'language'"
);
$term_id = 0;
foreach ( $languages as $row ) {
$description = unserialize( $row->description ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
if ( $description['locale'] === $locale ) {
$term_id = $row->term_taxonomy_id;
break;
}
}
$relevanssi_language_term_ids[ $locale ] = $term_id;
return $term_id;
}

View File

@@ -1,30 +0,0 @@
<?php
/**
* /lib/compatibility/pretty-links.php
*
* Pretty Links compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_admin_search_ok', 'relevanssi_pretty_links_ok', 10, 2 );
add_filter( 'relevanssi_prevent_default_request', 'relevanssi_pretty_links_ok', 10, 2 );
add_filter( 'relevanssi_search_ok', 'relevanssi_pretty_links_ok', 10, 2 );
/**
* Returns false if the query post type is set to 'pretty-link'.
*
* @param boolean $ok Whether to allow the query.
* @param WP_Query $query The WP_Query object.
*
* @return boolean False if this is a Pretty Links query.
*/
function relevanssi_pretty_links_ok( $ok, $query ) {
if ( isset( $query->query['post_type'] ) && 'pretty-link' === $query->query['post_type'] ) {
$ok = false;
}
return $ok;
}

View File

@@ -1,64 +0,0 @@
<?php
/**
* /lib/compatibility/product-gtin-ean-upc-isbn-for-woocommerce.php.php
*
* Adds Product GTIN (EAN, UPC, ISBN) for WooCommerce support for Relevanssi.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'pre_option_wpm_pgw_search_by_code', 'relevanssi_disable_gtin_code' );
add_filter( 'relevanssi_index_custom_fields', 'relevanssi_add_wpm_gtin_code' );
add_filter( 'option_relevanssi_index_fields', 'relevanssi_wpm_pgw_fix_none_setting' );
/**
* Disables the 'wpm_pgw_search_by_code' option.
*
* If this option is enabled, it will break Relevanssi search when there's a
* match for the code.
*
* @param string $value Not used.
*
* @return string 'no'.
*/
function relevanssi_disable_gtin_code( $value ) {
return 'no';
}
/**
* Adds the `_wpm_gtin_code` to the list of indexed custom fields.
*
* @param array|boolean $fields An array of custom fields to index, or false.
*
* @return array An array of custom fields, including `_wpm_gtin_code`.
*/
function relevanssi_add_wpm_gtin_code( $fields ) {
if ( ! is_array( $fields ) ) {
$fields = array();
}
if ( ! in_array( '_wpm_gtin_code', $fields, true ) ) {
$fields[] = '_wpm_gtin_code';
}
return $fields;
}
/**
* Makes sure the GTIN code is included in the index, even when the custom field
* setting is set to 'none'.
*
* @param string $value The custom field indexing setting value. The parameter
* is ignored, Relevanssi disables this filter and then checks the option to
* see what the value is.
*
* @return string If value is undefined, it's set to '_wpm_gtin_code'.
*/
function relevanssi_wpm_pgw_fix_none_setting( $value ) {
if ( ! $value ) {
$value = '_wpm_gtin_code';
}
return $value;
}

View File

@@ -1,100 +0,0 @@
<?php
/**
* /lib/compatibility/rankmath.php
*
* Rank Math noindex filtering function.
*
* @package Relevanssi
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_do_not_index', 'relevanssi_rankmath_noindex', 10, 2 );
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_rankmath_exclude' );
add_action( 'relevanssi_indexing_tab_advanced', 'relevanssi_rankmath_form', 20 );
add_action( 'relevanssi_indexing_options', 'relevanssi_rankmath_options' );
/**
* Blocks indexing of posts marked "noindex" in the Rank Math settings.
*
* Attaches to the 'relevanssi_do_not_index' filter hook.
*
* @param boolean $do_not_index True, if the post shouldn't be indexed.
* @param integer $post_id The post ID number.
*
* @return string|boolean If the post shouldn't be indexed, this returns
* 'RankMath'. The value may also be a boolean.
*/
function relevanssi_rankmath_noindex( $do_not_index, $post_id ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $do_not_index;
}
$noindex = get_post_meta( $post_id, 'rank_math_robots', true );
if ( is_array( $noindex ) && in_array( 'noindex', $noindex, true ) ) {
$do_not_index = 'RankMath';
}
return $do_not_index;
}
/**
* Excludes the "noindex" posts from Relevanssi indexing.
*
* Adds a MySQL query restriction that blocks posts that have the Rank Math
* "rank_math_robots" setting set to something that includes "noindex".
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_rankmath_exclude( $restriction ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $restriction;
}
global $wpdb;
// Backwards compatibility code for 2.8.0, remove at some point.
if ( is_string( $restriction ) ) {
$restriction = array(
'mysql' => $restriction,
'reason' => '',
);
}
$restriction['mysql'] .= " AND post.ID NOT IN (SELECT post_id FROM
$wpdb->postmeta WHERE meta_key = 'rank_math_robots'
AND meta_value LIKE '%noindex%' ) ";
$restriction['reason'] .= ' Rank Math';
return $restriction;
}
/**
* Prints out the form fields for disabling the feature.
*/
function relevanssi_rankmath_form() {
$seo_noindex = get_option( 'relevanssi_seo_noindex' );
$seo_noindex = relevanssi_check( $seo_noindex );
?>
<tr>
<th scope="row">
<label for='relevanssi_seo_noindex'><?php esc_html_e( 'Use Rank Math SEO noindex', 'relevanssi' ); ?></label>
</th>
<td>
<label for='relevanssi_seo_noindex'>
<input type='checkbox' name='relevanssi_seo_noindex' id='relevanssi_seo_noindex' <?php echo esc_attr( $seo_noindex ); ?> />
<?php esc_html_e( 'Use Rank Math SEO noindex.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will not index posts marked as "No index" in Rank Math SEO settings.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
}
/**
* Saves the SEO No index option.
*
* @param array $request An array of option values from the request.
*/
function relevanssi_rankmath_options( array $request ) {
relevanssi_update_off_or_on( $request, 'relevanssi_seo_noindex', true );
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* /lib/compatibility/restrictcontentpro.php
*
* Restrict Content Pro compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_restrictcontentpro_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_restrictcontentpro_compatibility( $post_ok, $post_id ) {
if ( ! $post_ok ) {
return $post_ok;
}
$post_ok = rcp_user_can_access( get_current_user_id(), $post_id );
return $post_ok;
}

View File

@@ -1,96 +0,0 @@
<?php
/**
* /lib/compatibility/seoframework.php
*
* The SEO Framework noindex filtering function.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_do_not_index', 'relevanssi_seoframework_noindex', 10, 2 );
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_seoframework_exclude' );
add_action( 'relevanssi_indexing_tab_advanced', 'relevanssi_seoframework_form', 20 );
add_action( 'relevanssi_indexing_options', 'relevanssi_seoframework_options' );
/**
* Blocks indexing of posts marked "Exclude this page from all search queries
* on this site." in the SEO Framework settings.
*
* Attaches to the 'relevanssi_do_not_index' filter hook.
*
* @param boolean $do_not_index True, if the post shouldn't be indexed.
* @param integer $post_id The post ID number.
*
* @return string|boolean If the post shouldn't be indexed, this returns
* 'SEO Framework'. The value may also be a boolean.
*/
function relevanssi_seoframework_noindex( $do_not_index, $post_id ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $do_not_index;
}
$noindex = get_post_meta( $post_id, 'exclude_local_search', true );
if ( '1' === $noindex ) {
$do_not_index = 'SEO Framework';
}
return $do_not_index;
}
/**
* Excludes the "noindex" posts from Relevanssi indexing.
*
* Adds a MySQL query restriction that blocks posts that have the SEO Framework
* "Exclude this page from all search queries on this site" setting set to "1"
* from indexing.
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_seoframework_exclude( $restriction ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $restriction;
}
global $wpdb;
$restriction['mysql'] .= " AND post.ID NOT IN (SELECT post_id FROM
$wpdb->postmeta WHERE meta_key = 'exclude_local_search'
AND meta_value = '1' ) ";
$restriction['reason'] .= ' SEO Framework';
return $restriction;
}
/**
* Prints out the form fields for disabling the feature.
*/
function relevanssi_seoframework_form() {
$seo_noindex = get_option( 'relevanssi_seo_noindex' );
$seo_noindex = relevanssi_check( $seo_noindex );
?>
<tr>
<th scope="row">
<label for='relevanssi_seo_noindex'><?php esc_html_e( 'Use SEO Framework noindex', 'relevanssi' ); ?></label>
</th>
<td>
<label for='relevanssi_seo_noindex'>
<input type='checkbox' name='relevanssi_seo_noindex' id='relevanssi_seo_noindex' <?php echo esc_attr( $seo_noindex ); ?> />
<?php esc_html_e( 'Use SEO Framework noindex.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will not index posts marked as "No index" in SEO Framework settings.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
}
/**
* Saves the SEO No index option.
*
* @param array $request An array of option values from the request.
*/
function relevanssi_seoframework_options( array $request ) {
relevanssi_update_off_or_on( $request, 'relevanssi_seo_noindex', true );
}

View File

@@ -1,102 +0,0 @@
<?php
/**
* /lib/compatibility/seopress.php
*
* SEOPress noindex filtering function.
*
* @package Relevanssi
* @author Benjamin Denis
* @source ./yoast-seo.php (Mikko Saari)
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_do_not_index', 'relevanssi_seopress_noindex', 10, 2 );
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_seopress_exclude' );
add_action( 'relevanssi_indexing_tab_advanced', 'relevanssi_seopress_form', 20 );
add_action( 'relevanssi_indexing_options', 'relevanssi_seopress_options' );
/**
* Blocks indexing of posts marked "noindex" in the SEOPress settings.
*
* Attaches to the 'relevanssi_do_not_index' filter hook.
*
* @param boolean $do_not_index True, if the post shouldn't be indexed.
* @param integer $post_id The post ID number.
*
* @return string|boolean If the post shouldn't be indexed, this returns
* 'seopress'. The value may also be a boolean.
*/
function relevanssi_seopress_noindex( $do_not_index, $post_id ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $do_not_index;
}
$noindex = get_post_meta( $post_id, '_seopress_robots_index', true );
if ( 'yes' === $noindex ) {
$do_not_index = 'SEOPress';
}
return $do_not_index;
}
/**
* Excludes the "noindex" posts from Relevanssi indexing.
*
* Adds a MySQL query restriction that blocks posts that have the SEOPress
* "noindex" setting set to "1" from indexing.
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_seopress_exclude( $restriction ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $restriction;
}
global $wpdb;
// Backwards compatibility code for 2.8.0, remove at some point.
if ( is_string( $restriction ) ) {
$restriction = array(
'mysql' => $restriction,
'reason' => '',
);
}
$restriction['mysql'] .= " AND post.ID NOT IN (SELECT post_id FROM
$wpdb->postmeta WHERE meta_key = '_seopress_robots_index'
AND meta_value = 'yes' ) ";
$restriction['reason'] .= 'SEOPress';
return $restriction;
}
/**
* Prints out the form fields for disabling the feature.
*/
function relevanssi_seopress_form() {
$seo_noindex = get_option( 'relevanssi_seo_noindex' );
$seo_noindex = relevanssi_check( $seo_noindex );
?>
<tr>
<th scope="row">
<label for='relevanssi_seo_noindex'><?php esc_html_e( 'Use SEOPress noindex', 'relevanssi' ); ?></label>
</th>
<td>
<label for='relevanssi_seo_noindex'>
<input type='checkbox' name='relevanssi_seo_noindex' id='relevanssi_seo_noindex' <?php echo esc_attr( $seo_noindex ); ?> />
<?php esc_html_e( 'Use SEOPress noindex.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will not index posts marked as "No index" in SEOPress settings.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
}
/**
* Saves the SEO No index option.
*
* @param array $request An array of option values from the request.
*/
function relevanssi_seopress_options( array $request ) {
relevanssi_update_off_or_on( $request, 'relevanssi_seo_noindex', true );
}

View File

@@ -1,30 +0,0 @@
<?php
/**
* /lib/compatibility/simplemembership.php
*
* Simple Membership compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_simplemembership_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_simplemembership_compatibility( $post_ok, $post_id ) {
$access_ctrl = SwpmAccessControl::get_instance();
$post = get_post( $post_id );
$post_ok = $access_ctrl->can_i_read_post( $post );
return $post_ok;
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* /lib/compatibility/tablepress.php
*
* TablePress compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Enables TablePress shortcodes for Relevanssi indexing.
*
* @return null|object The TablePress controller.
*/
function relevanssi_enable_tablepress_shortcodes() {
$my_tablepress_controller = null;
if ( defined( 'TABLEPRESS_ABSPATH' ) ) {
if ( ! isset( TablePress::$model_options ) ) {
include_once TABLEPRESS_ABSPATH . 'classes/class-model.php';
include_once TABLEPRESS_ABSPATH . 'models/model-options.php';
TablePress::$model_options = new TablePress_Options_Model();
}
$my_tablepress_controller = TablePress::load_controller( 'frontend' );
$my_tablepress_controller->init_shortcodes();
}
return $my_tablepress_controller;
}
add_filter( 'relevanssi_post_content', 'relevanssi_table_filter' );
/**
* Replaces the [table_filter] shortcodes with [table].
*
* The shortcode filter extension adds a [table_filter] shortcode which is not
* compatible with Relevanssi. This function switches those to the normal
* [table] shortcode which works better.
*
* @param string $content The post content.
*
* @return string The fixed post content.
*/
function relevanssi_table_filter( $content ) {
$content = str_replace( '[table_filter', '[table', $content );
return $content;
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* /lib/compatibility/useraccessmanager.php
*
* User Access Manager compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_useraccessmanager_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_useraccessmanager_compatibility( $post_ok, $post_id ) {
$status = relevanssi_get_post_status( $post_id );
if ( 'publish' === $status ) {
// Only apply to published posts, don't apply to drafts.
// phpcs:disable WordPress.NamingConventions.ValidVariableName
global $userAccessManager;
$type = relevanssi_get_post_type( $post_id );
$post_ok = $userAccessManager->getAccessHandler()->checkObjectAccess( $type, $post_id );
// phpcs:enable WordPress.NamingConventions.ValidVariableName
}
return $post_ok;
}

View File

@@ -1,282 +0,0 @@
<?php
/**
* /lib/compatibility/woocommerce.php
*
* WooCommerce compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_woocommerce_restriction' );
add_filter( 'relevanssi_admin_search_blocked_post_types', 'relevanssi_woocommerce_admin_search_blocked_post_types' );
add_filter( 'relevanssi_modify_wp_query', 'relevanssi_woocommerce_filters' );
/**
* This action solves the problems introduced by adjust_posts_count() in
* WooCommerce version 4.4.0.
*/
add_action( 'woocommerce_before_shop_loop', 'relevanssi_wc_reset_loop' );
RELEVANSSI_PREMIUM && add_filter( 'relevanssi_match', 'relevanssi_sku_boost' );
/**
* Resets the WC post loop in search queries.
*
* Hooks on to woocommerce_before_shop_loop.
*/
function relevanssi_wc_reset_loop() {
global $wp_query;
if ( $wp_query->is_search ) {
wc_reset_loop();
}
}
/**
* Applies the WooCommerce product visibility filter.
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_woocommerce_restriction( $restriction ) {
// Backwards compatibility code for 2.8.0, remove at some point.
if ( is_string( $restriction ) ) {
$restriction = array(
'mysql' => $restriction,
'reason' => '',
);
}
$restriction['mysql'] .= relevanssi_woocommerce_indexing_filter();
$restriction['reason'] .= 'WooCommerce';
return $restriction;
}
/**
* WooCommerce product visibility filtering for indexing.
*
* This filter is applied before the posts are selected for indexing, so this will
* skip all the excluded posts right away.
*
* @since 4.0.9 (2.1.5)
* @global $wpdb The WordPress database interface.
*
* @return string $restriction The query restriction for the WooCommerce filtering.
*/
function relevanssi_woocommerce_indexing_filter() {
global $wpdb;
$restriction = '';
$woocommerce_blocks = array(
'outofstock' => false,
'exclude-from-catalog' => false,
'exclude-from-search' => true,
);
/**
* Controls the WooCommerce product visibility filtering.
*
* @param array $woocommerce_blocks Has three keys: 'outofstock',
* 'exclude-from-catalog' and 'exclude-from-search', matching three different
* product visibility settings. If the filter sets some of these to 'true',
* those posts will be filtered in the indexing.
*/
$woocommerce_blocks = apply_filters( 'relevanssi_woocommerce_indexing', $woocommerce_blocks );
$term_taxonomy_id_array = array();
if ( $woocommerce_blocks['outofstock'] ) {
$out_of_stock = get_term_by( 'slug', 'outofstock', 'product_visibility', OBJECT );
if ( $out_of_stock && isset( $out_of_stock->term_taxonomy_id ) ) {
$term_taxonomy_id_array[] = $out_of_stock->term_taxonomy_id;
}
}
if ( $woocommerce_blocks['exclude-from-catalog'] ) {
$exclude_from_catalog = get_term_by( 'slug', 'exclude-from-catalog', 'product_visibility', OBJECT );
if ( $exclude_from_catalog && isset( $exclude_from_catalog->term_taxonomy_id ) ) {
$term_taxonomy_id_array[] = $exclude_from_catalog->term_taxonomy_id;
}
}
if ( $woocommerce_blocks['exclude-from-search'] ) {
$exclude_from_search = get_term_by( 'slug', 'exclude-from-search', 'product_visibility', OBJECT );
if ( $exclude_from_search && isset( $exclude_from_search->term_taxonomy_id ) ) {
$term_taxonomy_id_array[] = $exclude_from_search->term_taxonomy_id;
}
}
if ( ! empty( $term_taxonomy_id_array ) ) {
$term_taxonomy_id_string = implode( ',', $term_taxonomy_id_array );
$restriction .= " AND post.ID NOT IN (SELECT object_id FROM $wpdb->term_relationships WHERE object_id = post.ID AND term_taxonomy_id IN ($term_taxonomy_id_string)) ";
}
return $restriction;
}
/**
* SKU weight boost.
*
* Increases the weight for matches in the _sku custom field. The amount of
* boost can be adjusted with the `relevanssi_sku_boost` filter hook. The
* default is 2.
*
* @param object $match The match object.
*
* @return object The match object.
*/
function relevanssi_sku_boost( $match ) {
$custom_field_detail = json_decode( $match->customfield_detail );
if ( null !== $custom_field_detail && isset( $custom_field_detail->_sku ) ) {
/**
* Filters the SKU boost value.
*
* @param float The boost multiplier, default 2.
*/
$match->weight *= apply_filters( 'relevanssi_sku_boost', 2 );
}
return $match;
}
/**
* Adds blocked WooCommerce post types to the list of blocked post types.
*
* Stops Relevanssi from taking over the admin search for the WooCommerce
* blocked post types using the relevanssi_admin_search_blocked_post_types
* filter hook.
*
* @param array $post_types The list of blocked post types.
* @return array
*/
function relevanssi_woocommerce_admin_search_blocked_post_types( array $post_types ) : array {
$woo_post_types = array(
'shop_coupon',
'shop_order',
'shop_order_refund',
'wc_order_status',
'wc_order_email',
'shop_webhook',
);
return array_merge( $post_types, $woo_post_types );
}
/**
* Relevanssi support for WooCommerce filtering.
*
* @param WP_Query $query The WP_Query object.
* @return WP_Query The WP_Query object.
*/
function relevanssi_woocommerce_filters( $query ) {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$min_price = isset( $_REQUEST['min_price'] ) ? intval( $_REQUEST['min_price'] ) : false;
$max_price = isset( $_REQUEST['max_price'] ) ? intval( $_REQUEST['max_price'] ) : false;
$meta_query = $query->get( 'meta_query' );
if ( $min_price ) {
$meta_query[] = array(
'key' => '_price',
'value' => $min_price,
'compare' => '>=',
'type' => 'NUMERIC',
);
}
if ( $max_price ) {
$meta_query[] = array(
'key' => '_price',
'value' => $max_price,
'compare' => '<=',
'type' => 'NUMERIC',
);
}
if ( $meta_query ) {
$query->set( 'meta_query', $meta_query );
}
foreach ( array( 'product_tag', 'product_cat', 'product_brand' ) as $taxonomy ) {
$value = isset( $_REQUEST[ $taxonomy ] ) ? intval( $_REQUEST[ $taxonomy ] ) : false;
if ( $value ) {
$tax_query = $query->get( 'tax_query' );
if ( ! is_array( $tax_query ) ) {
$tax_query = array();
}
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $value,
);
$query->set( 'tax_query', $tax_query );
}
}
if ( 'no' === get_option( 'woocommerce_attribute_lookup_enabled' ) ) {
return $query;
}
$chosen_attributes = array();
if ( ! empty( $_GET ) ) {
foreach ( $_GET as $key => $value ) {
if ( 0 === strpos( $key, 'filter_' ) ) {
$attribute = wc_sanitize_taxonomy_name( str_replace( 'filter_', '', $key ) );
$taxonomy = wc_attribute_taxonomy_name( $attribute );
$filter_terms = ! empty( $value ) ? explode( ',', wc_clean( wp_unslash( $value ) ) ) : array();
if ( empty( $filter_terms ) || ! taxonomy_exists( $taxonomy ) || ! wc_attribute_taxonomy_id_by_name( $attribute ) ) {
continue;
}
$query_type = ! empty( $_GET[ 'query_type_' . $attribute ] ) && in_array( $_GET[ 'query_type_' . $attribute ], array( 'and', 'or' ), true )
? wc_clean( wp_unslash( $_GET[ 'query_type_' . $attribute ] ) )
: '';
$chosen_attributes[ $taxonomy ]['terms'] = array_map( 'sanitize_title', $filter_terms );
$chosen_attributes[ $taxonomy ]['query_type'] = $query_type ? $query_type : apply_filters( 'woocommerce_layered_nav_default_query_type', 'and' );
}
}
}
$tax_query = $query->get( 'tax_query' );
if ( ! is_array( $tax_query ) ) {
$tax_query = array();
}
foreach ( $chosen_attributes as $taxonomy => $data ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'slug',
'terms' => $data['terms'],
'operator' => 'and' === $data['query_type'] ? 'AND' : 'IN',
'include_children' => false,
);
}
$query->set( 'tax_query', $tax_query );
return $query;
}
/**
* Provides layered navigation term counts based on Relevanssi searches.
*
* Hooks onto woocommerce_get_filtered_term_product_counts_query to provide
* accurate term counts.
*
* @param array $query The MySQL query parts.
*
* @return array The modified query.
*/
function relevanssi_filtered_term_product_counts_query( $query ) {
if ( defined( 'BeRocket_AJAX_filters_version' ) ) {
return $query;
}
global $relevanssi_variables, $wpdb;
if ( false !== stripos( $query['select'], 'product_or_parent_id' ) ) {
$query['from'] = str_replace( 'FROM ', "FROM {$relevanssi_variables['relevanssi_table']} AS relevanssi, ", $query['from'] );
$query['where'] = str_replace( 'WHERE ', " WHERE relevanssi.doc = $wpdb->posts.ID AND ", $query['where'] );
$query['where'] = preg_replace( '/\(\w+posts.post_title LIKE(.*?)\)\)/', 'relevanssi.term LIKE\1)', $query['where'] );
$query['where'] = preg_replace( array( '/OR \(\w+posts.post_excerpt LIKE .*?\)/', '/OR \(\w+posts.post_content LIKE .*?\)/' ), '', $query['where'] );
} else {
$query['select'] = 'SELECT COUNT( DISTINCT( relevanssi.doc ) ) AS term_count, terms.term_id AS term_count_id';
$query['from'] = "FROM {$relevanssi_variables['relevanssi_table']} AS relevanssi, $wpdb->posts";
$query['where'] = str_replace( 'WHERE ', " WHERE relevanssi.doc = $wpdb->posts.ID AND ", $query['where'] );
$query['where'] = preg_replace( '/\(\w+posts.post_title LIKE(.*?)\)\)/', 'relevanssi.term LIKE\1)', $query['where'] );
$query['where'] = preg_replace( array( '/OR \(\w+posts.post_excerpt LIKE .*?\)/', '/OR \(\w+posts.post_content LIKE .*?\)/' ), '', $query['where'] );
}
return $query;
}

View File

@@ -1,58 +0,0 @@
<?php
/**
* /lib/compatibility/wp-file-download.php
*
* WP File Download compatibility features. Compatibility with WPFD checked for
* version 4.5.4.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_content_to_index', 'relevanssi_wpfd_content', 10, 2 );
add_action( 'wpfd_file_indexed', 'relevanssi_wpfd_index' );
/**
* Adds the WPFD indexed content to wpfd_file posts.
*
* Fetches the words from wpfd_words. wpfd_index.tid is the post ID, wpfd_index.id is
* then used to get the wpfd_docs.id, that is used to get the wpfd_vectors.did which
* can then be used to fetch the correct words from wpfd_words. This function is
* hooked onto relevanssi_content_to_index filter hook.
*
* @param string $content The post content as a string.
* @param object $post The post object.
*
* @return string The post content with the words added to the end.
*/
function relevanssi_wpfd_content( $content, $post ) {
$wpfd_search_config = get_option( '_wpfd_global_search_config', null );
if ( 'wpfd_file' === $post->post_type ) {
if ( $wpfd_search_config && isset( $wpfd_search_config['plain_text_search'] ) && $wpfd_search_config['plain_text_search'] ) {
global $wpdb;
$words = $wpdb->get_col(
"SELECT word
FROM {$wpdb->prefix}wpfd_words, {$wpdb->prefix}wpfd_docs, {$wpdb->prefix}wpfd_index, {$wpdb->prefix}wpfd_vectors " .
"WHERE {$wpdb->prefix}wpfd_index.tid = {$post->ID} " . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
" AND {$wpdb->prefix}wpfd_docs.index_id = {$wpdb->prefix}wpfd_index.id
AND {$wpdb->prefix}wpfd_docs.id = {$wpdb->prefix}wpfd_vectors.did
AND {$wpdb->prefix}wpfd_vectors.wid = {$wpdb->prefix}wpfd_words.id"
);
$content .= implode( ' ', $words );
}
}
return $content;
}
/**
* Runs Relevanssi indexing after WPFD indexing is done.
*
* @param int $wpfd_id The WPFD post index.
*/
function relevanssi_wpfd_index( $wpfd_id ) {
global $wpdb;
$post_id = $wpdb->get_var( $wpdb->prepare( "SELECT tid FROM {$wpdb->prefix}wpfd_index WHERE id=%d", $wpfd_id ) );
relevanssi_insert_edit( $post_id );
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* /lib/compatibility/wp-members.php
*
* WP-Members compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_wpmembers_compatibility', 10, 2 );
/**
* Checks whether the post type is blocked.
*
* Allows all logged-in users to see posts. For non-logged-in users, checks if
* the post is blocked by the _wpmem_block custom field, or if the post type is
* blocked in the $wpmem global.
*
* @param bool $post_ok Whether the user is allowed to see the post.
* @param int|string $post_id The post ID.
*
* @return bool
*/
function relevanssi_wpmembers_compatibility( bool $post_ok, $post_id ) : bool {
global $wpmem;
if ( is_user_logged_in() ) {
return $post_ok;
}
$post_meta = get_post_meta( $post_id, '_wpmem_block', true );
$post_type = isset( $wpmem->block[ relevanssi_get_post_type( $post_id ) ] )
? $wpmem->block[ relevanssi_get_post_type( $post_id ) ]
: 0;
if ( '1' === $post_meta ) {
$post_ok = false;
} elseif ( '1' === $post_type && '0' !== $post_meta ) {
$post_ok = false;
}
return $post_ok;
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* /lib/compatibility/wp-search-suggest.php
*
* WP Search Suggest compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'wpss_search_results', 'relevanssi_wpss_support', 10, 2 );
/**
* Adds Relevanssi results to WP Search Suggest dropdown.
*
* @param array $list List of post titles.
* @param object $query The WP_Query object.
*
* @return array List of post titles.
*/
function relevanssi_wpss_support( $list, $query ) {
$query = relevanssi_do_query( $query );
return wp_list_pluck( $query->posts, 'post_title' );
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* /lib/compatibility/wpjvpostreadinggroups.php
*
* WP JV Post Reading Groups compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_post_ok', 'relevanssi_wpjvpostreadinggroups_compatibility', 10, 2 );
/**
* Checks whether the user is allowed to see the post.
*
* @param boolean $post_ok Can the post be shown to the user.
* @param int $post_id The post ID.
*
* @return boolean $post_ok True if the user is allowed to see the post,
* otherwise false.
*/
function relevanssi_wpjvpostreadinggroups_compatibility( $post_ok, $post_id ) {
$post_ok = wp_jv_prg_user_can_see_a_post( get_current_user_id(), $post_id );
return $post_ok;
}

View File

@@ -1,149 +0,0 @@
<?php
/**
* /lib/compatibility/wpml.php
*
* WPML filtering function.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_hits_filter', 'relevanssi_wpml_filter', 9 );
add_filter( 'relevanssi_tag_before_tokenize', 'relevanssi_wpml_term_fix', 10, 4 );
/**
* Filters posts based on WPML language.
*
* Attaches to 'relevanssi_hits_filter' to restrict WPML searches to the current
* language. Whether this filter is used or not depends on the option
* 'relevanssi_wpml_only_current'. Thanks to rvencu for the initial code.
*
* @global object $sitepress The WPML global object.
*
* @param array $data Index 0 has the array of results, index 1 has the search query.
*
* @return array $data The whole parameter array, with the filtered posts in the index 0.
*/
function relevanssi_wpml_filter( $data ) {
$filter_enabled = get_option( 'relevanssi_wpml_only_current' );
if ( 'on' === $filter_enabled ) {
$wpml_post_type_setting = apply_filters( 'wpml_setting', false, 'custom_posts_sync_option' );
$wpml_taxonomy_setting = apply_filters( 'wpml_setting', false, 'taxonomies_sync_option' );
$current_blog_language = get_bloginfo( 'language' );
$filtered_hits = array();
foreach ( $data[0] as $hit ) {
$original_hit = $hit;
$object_array = relevanssi_get_an_object( $hit );
$hit = $object_array['object'];
if ( isset( $hit->blog_id ) ) {
// This is a multisite search.
switch_to_blog( $hit->blog_id );
if ( function_exists( 'icl_object_id' ) ) {
// Reset the WPML cache when blog is switched, otherwise WPML
// will be confused.
global $wpml_post_translations;
$wpml_post_translations->reload();
}
}
global $sitepress;
// Check if WPML is used.
if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
if ( $sitepress->is_translated_post_type( $hit->post_type ) ) {
$fallback_to_default = false;
if ( isset( $wpml_post_type_setting[ $hit->post_type ] ) && '2' === $wpml_post_type_setting[ $hit->post_type ] ) {
$fallback_to_default = true;
}
$id = apply_filters( 'wpml_object_id', $hit->ID, $hit->post_type, $fallback_to_default );
// This is a post in a translated post type.
if ( intval( $hit->ID ) === intval( $id ) ) {
// The post exists in the current language, and can be included.
$filtered_hits[] = $original_hit;
}
} elseif ( isset( $hit->term_id ) ) {
$fallback_to_default = false;
if ( isset( $wpml_taxonomy_setting[ $hit->post_type ] ) && '2' === $wpml_taxonomy_setting[ $hit->post_type ] ) {
$fallback_to_default = true;
}
if ( ! isset( $hit->post_type ) ) {
// This is a term object, not a Relevanssi-generated post object.
$hit->post_type = $hit->taxonomy;
}
$id = apply_filters( 'wpml_object_id', $hit->term_id, $hit->post_type, $fallback_to_default );
if ( intval( $hit->term_id ) === intval( $id ) ) {
// The post exists in the current language, and can be included.
$filtered_hits[] = $original_hit;
}
} else {
// This is not a translated post type, so include all posts.
$filtered_hits[] = $original_hit;
}
} elseif ( get_bloginfo( 'language' ) === $current_blog_language ) {
// If there is no WPML but the target blog has identical language with current blog,
// we use the hits. Note en-US is not identical to en-GB!
$filtered_hits[] = $original_hit;
}
if ( isset( $hit->blog_id ) ) {
restore_current_blog();
}
}
// A bit of foolproofing, avoid a warning if someone passes this filter bad data.
$query = '';
if ( isset( $data[1] ) ) {
$query = $data[1];
}
return array( $filtered_hits, $query );
}
return $data;
}
/**
* Fixes translated term indexing for WPML.
*
* WPML indexed translated terms based on current admin language, not the post
* language. This filter changes the term indexing to match the post language.
*
* @param string $term_content All terms in the taxonomy as a string.
* @param array $terms All the term objects in the current taxonomy.
* @param string $taxonomy The taxonomy name.
* @param int $post_id The post ID.
*
* @return string The term names as a string.
*/
function relevanssi_wpml_term_fix( string $term_content, array $terms, string $taxonomy, int $post_id ) {
$post_language = apply_filters( 'wpml_post_language_details', null, $post_id );
if ( ! is_wp_error( $post_language ) ) {
$term_content = '';
global $sitepress;
remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
foreach ( $terms as $term ) {
$term = get_term(
apply_filters(
'wpml_object_id',
$term->term_id,
$taxonomy,
true,
$post_language['language_code']
),
$taxonomy
);
$term_content .= ' ' . $term->name;
}
add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
}
return $term_content;
}

View File

@@ -1,102 +0,0 @@
<?php
/**
* /lib/compatibility/yoast-seo.php
*
* Yoast SEO noindex filtering function.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_do_not_index', 'relevanssi_yoast_noindex', 10, 2 );
add_filter( 'relevanssi_indexing_restriction', 'relevanssi_yoast_exclude' );
add_action( 'relevanssi_indexing_tab_advanced', 'relevanssi_yoast_form', 20 );
add_action( 'relevanssi_indexing_options', 'relevanssi_yoast_options' );
/**
* Blocks indexing of posts marked "noindex" in the Yoast SEO settings.
*
* Attaches to the 'relevanssi_do_not_index' filter hook.
*
* @param boolean $do_not_index True, if the post shouldn't be indexed.
* @param integer $post_id The post ID number.
*
* @return string|boolean If the post shouldn't be indexed, this returns
* 'yoast_seo'. The value may also be a boolean.
*/
function relevanssi_yoast_noindex( $do_not_index, $post_id ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $do_not_index;
}
$noindex = get_post_meta( $post_id, '_yoast_wpseo_meta-robots-noindex', true );
if ( '1' === $noindex ) {
$do_not_index = 'Yoast SEO';
}
return $do_not_index;
}
/**
* Excludes the "noindex" posts from Relevanssi indexing.
*
* Adds a MySQL query restriction that blocks posts that have the Yoast SEO
* "noindex" setting set to "1" from indexing.
*
* @param array $restriction An array with two values: 'mysql' for the MySQL
* query restriction to modify, 'reason' for the reason of restriction.
*/
function relevanssi_yoast_exclude( $restriction ) {
if ( 'on' !== get_option( 'relevanssi_seo_noindex' ) ) {
return $restriction;
}
global $wpdb;
// Backwards compatibility code for 2.8.0, remove at some point.
if ( is_string( $restriction ) ) {
$restriction = array(
'mysql' => $restriction,
'reason' => '',
);
}
$restriction['mysql'] .= " AND post.ID NOT IN (SELECT post_id FROM
$wpdb->postmeta WHERE meta_key = '_yoast_wpseo_meta-robots-noindex'
AND meta_value = '1' ) ";
$restriction['reason'] .= ' Yoast SEO';
return $restriction;
}
/**
* Prints out the form fields for disabling the feature.
*/
function relevanssi_yoast_form() {
$seo_noindex = get_option( 'relevanssi_seo_noindex' );
$seo_noindex = relevanssi_check( $seo_noindex );
?>
<tr>
<th scope="row">
<label for='relevanssi_seo_noindex'><?php esc_html_e( 'Use Yoast SEO noindex', 'relevanssi' ); ?></label>
</th>
<td>
<label for='relevanssi_seo_noindex'>
<input type='checkbox' name='relevanssi_seo_noindex' id='relevanssi_seo_noindex' <?php echo esc_attr( $seo_noindex ); ?> />
<?php esc_html_e( 'Use Yoast SEO noindex.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will not index posts marked as "No index" in Yoast SEO settings.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
}
/**
* Saves the SEO No index option.
*
* @param array $request An array of option values from the request.
*/
function relevanssi_yoast_options( array $request ) {
relevanssi_update_off_or_on( $request, 'relevanssi_seo_noindex', true );
}

View File

@@ -1,227 +0,0 @@
<?php
/**
* /lib/contextual-help.php
*
* Adds the contextual help menus.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Displays the contextual help menu.
*
* @global object $wpdb The WP database interface.
*/
function relevanssi_admin_help() {
global $wpdb;
$screen = get_current_screen();
// Translators: %1$s is 'orderby', %2$s is the Codex page URL.
$orderby_parameters = sprintf( __( "To adjust the post order, you can use the %1\$s query parameter. With %1\$s, you can use multiple layers of different sorting methods. See <a href='%2\$s'>WordPress Codex</a> for more details on using arrays for orderby.", 'relevanssi' ), '<code>orderby</code>', 'https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters' );
// Translators: %s is 'Uncheck this if you use non-ASCII characters' option name.
$inside_word_highlights = sprintf( __( 'To get inside-word highlights, uncheck the "%s" option. That has a side-effect of enabling the inside-word highlights.', 'relevanssi' ), __( 'Uncheck this if you use non-ASCII characters', 'relevanssi' ) );
// Translators: %s is 'relevanssi_throttle_limit'.
$throttle_limit = sprintf( __( 'In order to adjust the throttle limit, you can use the %s filter hook.', 'relevanssi' ), '<code>pre_option_relevanssi_throttle_limit</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-searching',
'title' => __( 'Searching', 'relevanssi' ),
'content' => '<ul>' .
"<li>$orderby_parameters</li>" .
'<li>' . __( "Inside-word matching is disabled by default, because it increases garbage results that don't really match the search term. If you want to enable it, add the following function to your theme functions.php:", 'relevanssi' ) .
'<pre>add_filter( \'relevanssi_fuzzy_query\', \'rlv_partial_inside_words\' );
function rlv_partial_inside_words( $query ) {
return "(relevanssi.term LIKE \'%#term#%\')";
}</pre></li>' .
"<li>$inside_word_highlights</li>" .
"<li>$throttle_limit" .
'<pre>add_filter( \'pre_option_relevanssi_throttle_limit\', function( $limit ) { return 200; } );</pre></li>' .
'<li>' . __( "It's not usually necessary to adjust the limit from 500, but in some cases performance gains can be achieved by setting a lower limit. We don't suggest going under 200, as low values will make the results worse.", 'relevanssi' ) . '</li>' .
'</ul>',
)
);
// Translators: %s is the link to the Codex page.
$codex_documentation = sprintf( __( 'For all the possible options, see the Codex documentation for %s.', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-search-restrictions',
'title' => __( 'Restrictions', 'relevanssi' ),
'content' => '<ul>' .
'<li>' . __( 'If you want the general search to target all posts, but have a single search form target only certain posts, you can add a hidden input variable to the search form. ', 'relevanssi' ) . '</li>' .
'<li>' . __( 'For example in order to restrict the search to categories 10, 14 and 17, you could add this to the search form:', 'relevanssi' ) .
'<pre>&lt;input type="hidden" name="cats" value="10,14,17" /&gt;</pre></li>' .
'<li>' . __( 'To restrict the search to posts tagged with alfa AND beta, you could add this to the search form:', 'relevanssi' ) .
'<pre>&lt;input type="hidden" name="tag" value="alfa+beta" /&gt;</pre></li>' .
"<li>$codex_documentation</li>" .
'</ul>',
)
);
// Translators: %s is the link to the Codex page.
$exclusion_options = sprintf( __( 'For more exclusion options, see the Codex documentation for %s. For example, to exclude tag ID 10, use', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' );
// Translators: %s is 'relevanssi_do_not_index'.
$exclusion_instructions = sprintf( __( 'To exclude posts from the index and not just from the search, you can use the %s filter hook. This would not index posts that have a certain taxonomy term:', 'relevanssi' ), '<code>relevanssi_do_not_index</code>' );
// Translators: %s is a link to the Relevanssi knowledge base.
$more_examples = sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_do_not_index/' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-search-exclusions',
'title' => __( 'Exclusions', 'relevanssi' ),
'content' => '<ul>' .
"<li>$exclusion_options" .
'<pre>&lt;input type="hidden" name="tag__not_in" value="10" /&gt;</pre></li>' .
"<li>$exclusion_instructions" .
'<pre>add_filter( \'relevanssi_do_not_index\', \'rlv_index_filter\', 10, 2 );
function rlv_index_filter( $block, $post_id ) {
if ( has_term( \'jazz\', \'genre\', $post_id ) ) {
$block = true;
}
return $block;
}
</pre></li>' .
"<li>$more_examples</li>" .
'</ul>',
)
);
// Translators: %s is 'relevanssi_user_searches_limit'.
$user_searches_limit = sprintf( __( 'By default, the User searches page shows 20 most common keywords. In order to see more, you can adjust the value with the %s filter hook, like this:', 'relevanssi' ), '<code>relevanssi_user_searches_limit</code>' );
// Translators: %s is the name of the database table.
$log_database = sprintf( __( 'The complete logs are stored in the %s database table, where you can access them if you need more information than what the User searches page provides.', 'relevanssi' ), '<code>' . $wpdb->prefix . 'relevanssi_log</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-logging',
'title' => __( 'Logs', 'relevanssi' ),
'content' => '<ul>' .
"<li>$user_searches_limit" .
"<pre>add_filter( 'relevanssi_user_searches_limit', function() { return 50; } );</pre></li>" .
"<li>$log_database</li>" .
'</ul>',
)
);
// Translators: %s is 'the_excerpt()'.
$custom_snippets = sprintf( __( 'Custom snippets require that the search results template uses %s to print out the excerpts.', 'relevanssi' ), '<code>the_excerpt()</code>' );
// Translators: %1$s is 'relevanssi_pre_excerpt_content', %2$s is 'relevanssi_excerpt_content'.
$pre_excerpt_content = sprintf( __( 'If you want more control over what content Relevanssi uses to create the excerpts, you can use the %1$s and %2$s filter hooks to adjust the content.', 'relevanssi' ), '<code>relevanssi_pre_excerpt_content</code>', '<code>relevanssi_excerpt_content</code>' );
// Translators: %s is 'relevanssi_disable_shortcodes_excerpt'.
$disable_shortcodes = sprintf( __( 'Some shortcode do not work well with Relevanssi excerpt-generation. Relevanssi disables some shortcodes automatically to prevent problems. This can be adjusted with the %s filter hook.', 'relevanssi' ), '<code>relevanssi_disable_shortcodes_excerpt</code>' );
// Translators: %s is 'relevanssi_optimize_excerpts'.
$optimize_excerpts = sprintf( __( "If you want Relevanssi to build excerpts faster and don't mind that they may be less than perfect in quality, add a filter that returns true on hook %s.", 'relevanssi' ), '<code>relevanssi_optimize_excerpts</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-excerpts',
'title' => __( 'Excerpts', 'relevanssi' ),
'content' => '<ul>' .
'<li>' . __( 'Building custom excerpts can be slow. If you are not actually using the excerpts, make sure you disable the option.', 'relevanssi' ) . '</li>' .
"<li>$custom_snippets</li>" .
'<li>' . __( 'Generally, Relevanssi generates the excerpts from post content. If you want to include custom field content in the excerpt-building, this can be done with a simple setting from the excerpt settings.', 'relevanssi' ) . '</li>' .
"<li>$pre_excerpt_content</li>" .
"<li>$disable_shortcodes</li>" .
"<li>$optimize_excerpts" .
"<pre>add_filter( 'relevanssi_optimize_excerpts', '__return_true' );</pre></li>" .
'</ul>',
)
);
// Translators: %1$s is 'the_title()', %2$s is 'relevanssi_the_title()'.
$the_title = sprintf( __( 'In order to see title highlights from Relevanssi, replace %1$s in the search results template with %2$s. It does the same thing, but supports Relevanssi title highlights.', 'relevanssi' ), '<code>the_title()</code>', '<code>relevanssi_the_title()</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-highlights',
'title' => __( 'Highlights', 'relevanssi' ),
'content' => '<ul>' .
'<li>' . __( "Title highlights don't appear automatically, because that led to problems with highlights appearing in wrong places and messing up navigation menus, for example.", 'relevanssi' ) . '</li>' .
"<li>$the_title</li>" .
'</ul>',
)
);
// Translators: %1$s is 'relevanssi_punctuation_filter', %2$s is 'relevanssi_remove_punctuation'.
$remove_punctuation = sprintf( __( 'For more fine-tuned changes, you can use %1$s filter hook to adjust what is replaced with what, and %2$s filter hook to completely override the default punctuation control.', 'relevanssi' ), '<code>relevanssi_punctuation_filter</code>', '<code>relevanssi_remove_punctuation</code>' );
// Translators: %s is the URL to the Knowledge Base entry.
$remove_punct_guide = sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_remove_punct/' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-punctuation',
'title' => __( 'Punctuation', 'relevanssi' ),
'content' => '<ul>' .
'<li>' . __( 'Relevanssi removes punctuation. Some punctuation is removed, some replaced with spaces. Advanced indexing settings include some of the more common settings people want to change.', 'relevanssi' ) . '</li>' .
"<li>$remove_punctuation</li>" .
"<li>$remove_punct_guide</li>" .
'</ul>',
)
);
// Translators: %s is '[noindex]'.
$noindex = sprintf( __( "If you have content that you don't want indexed, you can wrap that content in a %s shortcode.", 'relevanssi' ), '<code>[noindex]</code>' );
// Translators: %s is '[searchform]'.
$searchform = sprintf( __( 'If you need a search form on some page on your site, you can use the %s shortcode to print out a basic search form.', 'relevanssi' ), '<code>[searchform]</code>' );
// Translators: %1$s is '[searchform post_types="page"]', %2$s is '[searchform cats="10,14,17"]'.
$searchform_cats = sprintf( __( 'If you need to add query variables to the search form, the shortcode takes parameters, which are then printed out as hidden input fields. To get a search form with a post type restriction, you can use %1$s. To restrict the search to categories 10, 14 and 17, you can use %2$s and so on.', 'relevanssi' ), '<code>[searchform post_types="page"]</code>', '<code>[searchform cats="10,14,17"]</code>' );
// Translators: %1$s is 'dropdown', %2$s is '[searchform dropdown="category"]'.
$searchform_dropdown = sprintf( __( 'You can use the %1$s parameter to add a taxonomy dropdown to the search form. Just use the name of the taxonomy, like %2$s. This works best with hierarchical taxonomies like categories with relatively few options available.', 'relevanssi' ), '<code>dropdown</code>', '<code>[searchform dropdown="category"]</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-helpful-shortcodes',
'title' => __( 'Helpful shortcodes', 'relevanssi' ),
'content' => "<ul>
<li>$noindex</li>
<li>$searchform</li>
<li>$searchform_cats</li>
<li>$searchform_dropdown</li>
</ul>",
)
);
// Translators: %s is the Knowledge Base URL.
$woocommerce = sprintf( __( "For more details how to fix that issue, see <a href='%s'>WooCommerce tips in Relevanssi user manual</a>.", 'relevanssi' ), 'https://www.relevanssi.com/user-manual/woocommerce/' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-title-woocommerce',
'title' => __( 'WooCommerce', 'relevanssi' ),
'content' => '<ul>' .
'<li>' . __( "If your SKUs include hyphens or other punctuation, do note that Relevanssi replaces most punctuation with spaces. That's going to cause issues with SKU searches.", 'relevanssi' ) . '</li>' .
"<li>$woocommerce</li>" .
'<li>' . __( "If you don't want to index products that are out of stock, excluded from the catalog or excluded from the search, there's a product visibility filtering method that is described in the user manual (see link above).", 'relevanssi' ) . '</li>' .
'</ul>',
)
);
// Translators: %s is the name of the filter hook.
$exact_match_bonus = sprintf( __( 'To adjust the amount of the exact match bonus, you can use the %s filter hook. It works like this:', 'relevanssi' ), '<code>relevanssi_exact_match_bonus</code>' );
// Translators: %1$s is the title weight and %2$s is the content weight.
$weights = sprintf( esc_html__( 'The default values are %1$s for titles and %2$s for content.', 'relevanssi' ), '<code>5</code>', '<code>2</code>' );
$screen->add_help_tab(
array(
'id' => 'relevanssi-exact-match',
'title' => __( 'Exact match bonus', 'relevanssi' ),
'content' => '<ul>' .
"<li>$exact_match_bonus" .
"<pre>add_filter( 'relevanssi_exact_match_bonus', 'rlv_adjust_bonus' );
function rlv_adjust_bonus( \$bonus ) {
return array( 'title' => 10, 'content' => 5 );
}</li>" .
"<li>$weights</ul>",
)
);
$screen->set_help_sidebar(
'<p><strong>' . __( 'For more information:', 'relevanssi' ) . '</strong></p>' .
'<p><a href="https://www.relevanssi.com/knowledge-base/" target="_blank">' . __( 'Plugin knowledge base', 'relevanssi' ) . '</a></p>' .
'<p><a href="https://wordpress.org/tags/relevanssi?forum_id=10" target="_blank">' . __( 'WordPress.org forum', 'relevanssi' ) . '</a></p>'
);
}

View File

@@ -1,161 +0,0 @@
<?php
/**
* /lib/debug.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'wp', 'relevanssi_debug_post' );
/**
* Checks if Relevanssi debug mode is enabled.
*
* Debug mode is enabled by setting RELEVANSSI_DEBUG to true or with the
* 'relevanssi_debug' query parameter if the debug mode is allowed from the
* settings.
*
* @return boolean True if debug mode is enabled, false if not.
*/
function relevanssi_is_debug() : bool {
$debug = false;
if ( defined( 'RELEVANSSI_DEBUG' ) && RELEVANSSI_DEBUG ) {
$debug = true;
}
if ( isset( $_REQUEST['relevanssi_debug'] ) && 'on' === get_option( 'relevanssi_debugging_mode' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$debug = true;
}
return $debug;
}
/**
* Adds the debug information to the search results.
*
* Displays the found posts.
*
* @param array $posts The search results.
*/
function relevanssi_debug_posts( $posts ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<h2>Posts</h2>';
foreach ( $posts as $post ) {
if ( ! is_object( $post ) ) {
echo "$post\n";
} else {
echo "<p>$post->ID: $post->post_title<br />";
echo "$post->post_type $post->post_status $post->relevance_score<br />";
echo "relevanssi_link: $post->relevanssi_link<br />";
echo 'the_permalink(): ';
the_permalink( $post->ID );
echo '<br />get_permalink(): ' . get_permalink( $post );
echo '</p>';
}
}
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Prints out an array in a preformatted block.
*
* @param array $array The array to print.
* @param string $title The title for the array.
*/
function relevanssi_debug_array( $array, $title ) {
echo '<h2>' . esc_html( $title ) . '</h2>';
echo '<pre>';
print_r( $array ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
echo '</pre>';
}
/**
* Prints out a string in a preformatted block.
*
* @param string $string The string to print.
* @param string $title The title for the string.
*/
function relevanssi_debug_string( $string, $title ) {
echo '<h2>' . esc_html( $title ) . '</h2>';
echo '<pre>' . esc_html( $string ) . '</pre>';
}
/**
* Prints out the Relevanssi debug information for a post.
*
* This function is called by the 'wp' action, so it's executed on every page
* load.
*/
function relevanssi_debug_post() {
if ( ! is_singular() || ! relevanssi_is_debug() ) {
return;
}
global $post;
echo '<h1>' . esc_html( $post->post_title ) . ' (' . intval( $post->ID ) . ')</h1>';
echo '<h2>Index</h2>';
echo relevanssi_generate_how_relevanssi_sees( $post->ID, true, 'post' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<h2>Database</h2>';
echo '<pre>' . relevanssi_generate_db_post_view( $post->ID ) . '</pre>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
relevanssi_debug_array( get_post_meta( $post->ID ), 'Post meta' );
exit();
}
/**
* Generates the debugging view for a post.
*
* @param int $post_id ID of the post.
*
* @return string The debugging view in a div container.
*/
function relevanssi_generate_db_post_view( int $post_id ) {
global $wpdb;
$element = '<div id="relevanssi_db_view_container">';
$post_object = get_post( $post_id );
if ( ! $post_object ) {
$element .= '<p>' . esc_html__( 'Post not found', 'relevanssi' ) . '</p>';
$element .= '</div>';
return $element;
}
$element .= '<p>' . esc_html( $post_object->post_content ) . '</p>';
$element .= '</div>';
return $element;
}
/**
* Prints out the Relevanssi debug information for search settings.
*/
function relevanssi_debug_search_settings() {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<h2>Relevanssi searching settings</h2>';
echo '<p>';
$value = get_option( 'relevanssi_fuzzy' );
echo "relevanssi_fuzzy: $value<br />";
$value = get_option( 'relevanssi_implicit_operator' );
echo "relevanssi_implicit_operator: $value<br />";
$value = get_option( 'relevanssi_disable_or_fallback' );
echo "relevanssi_disable_or_fallback: $value<br />";
$value = get_option( 'relevanssi_throttle' );
echo "relevanssi_throttle: $value<br />";
$value = get_option( 'relevanssi_throttle_limit' );
echo "relevanssi_throttle_limit: $value<br />";
$value = get_option( 'relevanssi_default_orderby' );
echo "relevanssi_default_orderby: $value<br />";
echo '</p>';
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
}

View File

@@ -1,221 +0,0 @@
<?php
/**
* /lib/didyoumean.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Generates the Did you mean suggestions.
*
* A wrapper function that prints out the Did you mean suggestions. If Premium
* is available, will use relevanssi_premium_didyoumean(), otherwise the
* relevanssi_simple_didyoumean() is used.
*
* @param string $query The query.
* @param string $pre Printed out before the suggestion.
* @param string $post Printed out after the suggestion.
* @param int $n Maximum number of search results found for the
* suggestions to show up. Default 5.
* @param boolean $echo If true, echo out. Default true.
*
* @return string|null The suggestion HTML element.
*/
function relevanssi_didyoumean( $query, $pre, $post, $n = 5, $echo = true ) {
if ( function_exists( 'relevanssi_premium_didyoumean' ) ) {
$result = relevanssi_premium_didyoumean( $query, $pre, $post, $n );
} else {
$result = relevanssi_simple_didyoumean( $query, $pre, $post, $n );
}
if ( $echo ) {
echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
return $result;
}
/**
* Generates the Did you mean suggestions HTML code.
*
* Uses relevanssi_simple_generate_suggestion() to come up with a suggestion,
* then wraps that up with HTML code.
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The Relevanssi global variables.
* @global object $wp_query The WP_Query object.
*
* @param string $query The query.
* @param string $pre Printed out before the suggestion.
* @param string $post Printed out after the suggestion.
* @param int $n Maximum number of search results found for the
* suggestions to show up. Default 5.
*
* @return string|null The suggestion HTML code, null if nothing found.
*/
function relevanssi_simple_didyoumean( $query, $pre, $post, $n = 5 ) {
global $wp_query;
$total_results = $wp_query->found_posts;
if ( $total_results > $n ) {
return null;
}
$suggestion = relevanssi_simple_generate_suggestion( $query );
$result = null;
if ( $suggestion ) {
$url = trailingslashit( get_bloginfo( 'url' ) );
$url = esc_attr(
add_query_arg(
array( 's' => rawurlencode( $suggestion ) ),
$url
)
);
/**
* Filters the 'Did you mean' suggestion URL.
*
* @param string $url The URL for the suggested search query.
* @param string $query The search query.
* @param string $suggestion The suggestion.
*/
$url = apply_filters(
'relevanssi_didyoumean_url',
$url,
$query,
$suggestion
);
// Escape the suggestion to avoid XSS attacks.
$suggestion = htmlspecialchars( $suggestion );
/**
* Filters the complete 'Did you mean' suggestion.
*
* @param string The suggestion HTML code.
*/
$result = apply_filters(
'relevanssi_didyoumean_suggestion',
"$pre<a href='$url'>$suggestion</a>$post"
);
}
return $result;
}
/**
* Generates the 'Did you mean' suggestions. Can be used to correct any queries.
*
* Uses the Relevanssi search logs as source material for corrections. If there
* are no logged search queries, can't do anything.
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The Relevanssi global variables, used
* for table names.
*
* @param string $query The query to correct.
*
* @return string Corrected query, empty if nothing found.
*/
function relevanssi_simple_generate_suggestion( $query ) {
global $wpdb, $relevanssi_variables;
/**
* The minimum limit of occurrances to include a word.
*
* To save resources, only words with more than this many occurrances are
* fed for the spelling corrector. If there are problems with the spelling
* corrector, increasing this value may fix those problems.
*
* @param int $number The number of occurrances must be more than this
* value, default 2.
*/
$count = apply_filters( 'relevanssi_get_words_having', 2 );
if ( ! is_numeric( $count ) ) {
$count = 2;
}
$q = 'SELECT query, count(query) as c, AVG(hits) as a FROM '
. $relevanssi_variables['log_table'] . ' WHERE hits > ' . $count
. ' GROUP BY query ORDER BY count(query) DESC';
/**
* Filters the MySQL query used to fetch potential suggestions from the log.
*
* @param string $q MySQL query for fetching the suggestions.
*/
$q = apply_filters( 'relevanssi_didyoumean_query', $q );
$data = get_transient( 'relevanssi_didyoumean_query' );
if ( empty( $data ) ) {
$data = $wpdb->get_results( $q ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
set_transient( 'relevanssi_didyoumean_query', $data, MONTH_IN_SECONDS );
}
$query = htmlspecialchars_decode( $query, ENT_QUOTES );
$tokens = relevanssi_tokenize( $query, true, -1, 'search_query' );
$suggestions_made = false;
$suggestion = '';
foreach ( $tokens as $token => $count ) {
/**
* Filters the tokens for Did you mean suggestions.
*
* You can use this filter hook to modify the tokens before Relevanssi
* tries to come up with Did you mean suggestions for them. If you
* return an empty string, the token will be skipped and no suggestion
* will be made for the token.
*
* @param string $token An individual word from the search query.
*
* @return string The token.
*/
$token = apply_filters( 'relevanssi_didyoumean_token', trim( $token ) );
if ( ! $token ) {
continue;
}
$closest = '';
$distance = -1;
foreach ( $data as $row ) {
if ( $row->c < 2 ) {
break;
}
if ( $token === $row->query ) {
$closest = '';
break;
} else {
if ( strlen( $token ) < 255 && strlen( $row->query ) < 255 ) {
// The levenshtein() function has a max length of 255
// characters. The function uses strlen(), so we must use
// too, instead of relevanssi_strlen().
$lev = levenshtein( $token, $row->query );
if ( $lev < 3 && ( $lev < $distance || $distance < 0 ) ) {
if ( $row->a > 0 ) {
$distance = $lev;
$closest = $row->query;
if ( $lev < 2 ) {
break; // get the first with distance of 1 and go.
}
}
}
}
}
}
if ( ! empty( $closest ) ) {
$query = str_ireplace( $token, $closest, $query, $replacement_count );
if ( $replacement_count > 0 ) {
$suggestions_made = true;
}
}
}
if ( $suggestions_made ) {
$suggestion = $query;
}
return $suggestion;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,541 +0,0 @@
<?php
/**
* /lib/init.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
// Setup.
add_action( 'init', 'relevanssi_init', 1 );
add_filter( 'query_vars', 'relevanssi_query_vars' );
add_filter( 'rest_api_init', 'relevanssi_rest_api_disable' );
add_action( 'switch_blog', 'relevanssi_switch_blog', 1, 2 );
add_action( 'admin_init', 'relevanssi_admin_init' );
add_action( 'admin_menu', 'relevanssi_menu' );
// Taking over the search.
add_filter( 'posts_pre_query', 'relevanssi_query', 99, 2 );
add_filter( 'posts_request', 'relevanssi_prevent_default_request', 10, 2 );
add_filter( 'relevanssi_search_ok', 'relevanssi_block_on_admin_searches', 10, 2 );
add_filter( 'relevanssi_admin_search_ok', 'relevanssi_block_on_admin_searches', 10, 2 );
add_filter( 'relevanssi_prevent_default_request', 'relevanssi_block_on_admin_searches', 10, 2 );
add_filter( 'relevanssi_search_ok', 'relevanssi_control_media_queries', 11, 2 );
// Post indexing.
global $wp_version;
if ( version_compare( $wp_version, '5.6', '>=' ) ) {
add_action( 'wp_after_insert_post', 'relevanssi_insert_edit', 99, 1 );
} else {
add_action( 'wp_insert_post', 'relevanssi_insert_edit', 99, 1 );
}
add_action( 'delete_post', 'relevanssi_remove_doc' );
// Comment indexing.
add_action( 'comment_post', 'relevanssi_index_comment' );
add_action( 'edit_comment', 'relevanssi_index_comment' );
add_action( 'trashed_comment', 'relevanssi_index_comment' );
add_action( 'deleted_comment', 'relevanssi_index_comment' );
// Attachment indexing.
add_action( 'delete_attachment', 'relevanssi_remove_doc' );
add_action( 'add_attachment', 'relevanssi_insert_edit', 12 );
add_action( 'edit_attachment', 'relevanssi_insert_edit' );
// When a post status changes, check child posts that inherit their status from parent.
add_action( 'transition_post_status', 'relevanssi_update_child_posts', 99, 3 );
// Relevanssi features.
add_filter( 'relevanssi_remove_punctuation', 'remove_accents', 9 );
add_filter( 'relevanssi_remove_punctuation', 'relevanssi_remove_punct' );
add_filter( 'relevanssi_post_ok', 'relevanssi_default_post_ok', 9, 2 );
add_filter( 'relevanssi_query_filter', 'relevanssi_limit_filter' );
add_action( 'relevanssi_trim_logs', 'relevanssi_trim_logs' );
add_action( 'relevanssi_update_counts', 'relevanssi_update_counts' );
add_action( 'relevanssi_custom_field_value', 'relevanssi_filter_custom_fields', 10, 2 );
add_filter( 'relevanssi_index_custom_fields', 'relevanssi_remove_metadata_fields' );
add_filter( 'relevanssi_join', 'relevanssi_post_date_throttle_join', 1 );
add_filter( 'relevanssi_where', 'relevanssi_post_date_throttle_where', 1 );
// Excerpts and highlights.
add_action( 'relevanssi_pre_the_content', 'relevanssi_kill_autoembed' );
add_action( 'relevanssi_pre_the_content', 'relevanssi_excerpt_pre_the_content' );
add_action( 'relevanssi_post_the_content', 'relevanssi_excerpt_post_the_content' );
// Page builder shortcodes.
add_filter( 'relevanssi_pre_excerpt_content', 'relevanssi_remove_page_builder_shortcodes', 9 );
add_filter( 'relevanssi_post_content', 'relevanssi_remove_page_builder_shortcodes', 9 );
// Permalink handling.
add_filter( 'post_link', 'relevanssi_permalink', 10, 2 );
add_filter( 'post_type_link', 'relevanssi_permalink', 10, 2 );
add_filter( 'attachment_link', 'relevanssi_permalink', 10, 2 );
add_filter( 'page_link', 'relevanssi_permalink', 10, 2 );
add_filter( 'relevanssi_permalink', 'relevanssi_permalink' );
// Log exports.
add_action( 'plugins_loaded', 'relevanssi_export_log_check' );
global $relevanssi_variables;
register_activation_hook( $relevanssi_variables['file'], 'relevanssi_install' );
/**
* Initiates Relevanssi.
*
* @global string $pagenow Current admin page.
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_init() {
global $pagenow, $relevanssi_variables;
$plugin_dir = dirname( plugin_basename( $relevanssi_variables['file'] ) );
load_plugin_textdomain( 'relevanssi', false, $plugin_dir . '/languages' );
$on_relevanssi_page = false;
if ( isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$page = sanitize_file_name( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$base = sanitize_file_name( wp_unslash( plugin_basename( $relevanssi_variables['file'] ) ) );
if ( $base === $page ) {
$on_relevanssi_page = true;
}
}
$restriction_notice = relevanssi_check_indexing_restriction();
if ( $restriction_notice ) {
if ( 'options-general.php' === $pagenow && $on_relevanssi_page ) {
if ( 'indexing' === $_GET['tab'] ) { // phpcs:ignore WordPress.Security.NonceVerification
add_action(
'admin_notices',
function() use ( $restriction_notice ) {
echo $restriction_notice; // phpcs:ignore WordPress.Security.EscapeOutput
}
);
}
}
}
if ( 'done' !== get_option( 'relevanssi_indexed' ) ) {
if ( 'options-general.php' === $pagenow && $on_relevanssi_page ) {
add_action(
'admin_notices',
function() {
printf(
"<div id='relevanssi-warning' class='update-nag'><p><strong>%s</strong></p></div>",
esc_html__( 'You do not have an index! Remember to build the index (click the "Build the index" button), otherwise searching won\'t work.', 'relevanssi' )
);
}
);
}
}
if ( ! function_exists( 'mb_internal_encoding' ) ) {
/**
* Prints out the "Multibyte string functions are not available" warning.
*/
function relevanssi_mb_warning() {
printf( "<div id='relevanssi-warning' class='error'><p><strong>%s</strong></p></div>", esc_html__( 'Multibyte string functions are not available. Relevanssi may not work well without them. Please install (or ask your host to install) the mbstring extension.', 'relevanssi' ) );
}
if ( 'options-general.php' === $pagenow && $on_relevanssi_page ) {
add_action( 'admin_notices', 'relevanssi_mb_warning' );
}
}
if ( 'off' !== get_option( 'relevanssi_highlight_docs', 'off' ) ) {
add_filter( 'the_content', 'relevanssi_highlight_in_docs', 11 );
}
if ( 'off' !== get_option( 'relevanssi_highlight_comments', 'off' ) ) {
add_filter( 'comment_text', 'relevanssi_highlight_in_docs', 11 );
}
if ( get_option( 'relevanssi_trim_logs' ) > 0 ) {
if ( ! wp_next_scheduled( 'relevanssi_trim_logs' ) ) {
wp_schedule_event( time(), 'daily', 'relevanssi_trim_logs' );
}
} else {
if ( wp_next_scheduled( 'relevanssi_trim_logs' ) ) {
wp_clear_scheduled_hook( 'relevanssi_trim_logs' );
}
}
if ( ! wp_next_scheduled( 'relevanssi_update_counts' ) ) {
wp_schedule_event( time(), 'weekly', 'relevanssi_update_counts' );
}
relevanssi_load_compatibility_code();
if ( ! is_array( get_option( 'relevanssi_stopwords' ) ) ) {
// Version 2.12 / 4.10 changes stopwords option from a string to an
// array to support multilingual stopwords. This function converts old
// style to new style. Remove eventually.
relevanssi_update_stopwords_setting();
}
if ( ! is_array( get_option( 'relevanssi_synonyms' ) ) ) {
// Version 2.12 / 4.10 changes synonyms option from a string to an
// array to support multilingual synonyms. This function converts old
// style to new style. Remove eventually.
relevanssi_update_synonyms_setting();
}
do_action( 'relevanssi_init' );
}
/**
* Iniatiates Relevanssi for admin.
*
* @global array $relevanssi_variables Global Relevanssi variables array.
*/
function relevanssi_admin_init() {
global $relevanssi_variables;
add_action( 'admin_enqueue_scripts', 'relevanssi_add_admin_scripts' );
add_filter( 'plugin_action_links_' . $relevanssi_variables['plugin_basename'], 'relevanssi_action_links' );
relevanssi_create_database_tables( $relevanssi_variables['database_version'] );
}
/**
* Adds the Relevanssi menu items.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_menu() {
global $relevanssi_variables;
$name = 'Relevanssi';
if ( RELEVANSSI_PREMIUM ) {
$name = 'Relevanssi Premium';
}
$plugin_page = add_options_page(
$name,
$name,
/**
* Filters the capability required to access Relevanssi options.
*
* @param string The capability required. Default 'manage_options'.
*/
apply_filters( 'relevanssi_options_capability', 'manage_options' ),
$relevanssi_variables['file'],
'relevanssi_options'
);
add_dashboard_page(
__( 'User searches', 'relevanssi' ),
__( 'User searches', 'relevanssi' ),
/**
* Filters the capability required to access Relevanssi user searches page.
*
* @param string The capability required. Default 'edit_pages'.
*/
apply_filters( 'relevanssi_user_searches_capability', 'edit_pages' ),
$relevanssi_variables['file'],
'relevanssi_search_stats'
);
add_dashboard_page(
__( 'Admin search', 'relevanssi' ),
__( 'Admin search', 'relevanssi' ),
/**
* Filters the capability required to access Relevanssi admin search page.
*
* @param string The capability required. Default 'edit_posts'.
*/
apply_filters( 'relevanssi_admin_search_capability', 'edit_posts' ),
'relevanssi_admin_search',
'relevanssi_admin_search_page'
);
require_once 'contextual-help.php';
add_action( 'load-' . $plugin_page, 'relevanssi_admin_help' );
if ( function_exists( 'relevanssi_premium_plugin_page_actions' ) ) {
// Loads contextual help and JS for Premium version.
relevanssi_premium_plugin_page_actions( $plugin_page );
}
}
/**
* Introduces the Relevanssi query variables.
*
* Adds the Relevanssi query variables (cats, tags, post_types, by_date, and
* highlight) to the WordPress whitelist of accepted query variables.
*
* @param array $qv The query variable list.
*
* @return array The query variables.
*/
function relevanssi_query_vars( $qv ) {
$qv[] = 'cats';
$qv[] = 'tags';
$qv[] = 'post_types';
$qv[] = 'by_date';
$qv[] = 'highlight';
$qv[] = 'posts_per_page';
$qv[] = 'post_parent';
$qv[] = 'post_status';
return $qv;
}
/**
* Creates the Relevanssi database tables.
*
* @global object $wpdb The WordPress database interface.
*
* @param int $relevanssi_db_version The Relevanssi database version number.
*/
function relevanssi_create_database_tables( $relevanssi_db_version ) {
global $wpdb;
$current_db_version = intval( get_option( 'relevanssi_db_version' ) );
if ( $current_db_version === $relevanssi_db_version ) {
return;
}
$charset_collate_bin_column = '';
$charset_collate = '';
if ( ! empty( $wpdb->charset ) ) {
$charset_collate_bin_column = "CHARACTER SET $wpdb->charset";
$charset_collate = "DEFAULT $charset_collate_bin_column";
}
if ( strpos( $wpdb->collate, '_' ) > 0 ) {
$charset_collate_bin_column .= ' COLLATE ' . substr( $wpdb->collate, 0, strpos( $wpdb->collate, '_' ) ) . '_bin';
$charset_collate .= " COLLATE $wpdb->collate";
} else {
if ( '' === $wpdb->collate && 'utf8' === $wpdb->charset ) {
$charset_collate_bin_column .= ' COLLATE utf8_bin';
}
}
$relevanssi_table = $wpdb->prefix . 'relevanssi';
$relevanssi_stopword_table = $wpdb->prefix . 'relevanssi_stopwords';
$relevanssi_log_table = $wpdb->prefix . 'relevanssi_log';
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$sql = 'CREATE TABLE ' . $relevanssi_table . " (doc bigint(20) NOT NULL DEFAULT '0',
term varchar(50) NOT NULL DEFAULT '0',
term_reverse varchar(50) NOT NULL DEFAULT '0',
content mediumint(9) NOT NULL DEFAULT '0',
title mediumint(9) NOT NULL DEFAULT '0',
comment mediumint(9) NOT NULL DEFAULT '0',
tag mediumint(9) NOT NULL DEFAULT '0',
link mediumint(9) NOT NULL DEFAULT '0',
author mediumint(9) NOT NULL DEFAULT '0',
category mediumint(9) NOT NULL DEFAULT '0',
excerpt mediumint(9) NOT NULL DEFAULT '0',
taxonomy mediumint(9) NOT NULL DEFAULT '0',
customfield mediumint(9) NOT NULL DEFAULT '0',
mysqlcolumn mediumint(9) NOT NULL DEFAULT '0',
taxonomy_detail longtext NOT NULL,
customfield_detail longtext NOT NULL DEFAULT '',
mysqlcolumn_detail longtext NOT NULL DEFAULT '',
type varchar(210) NOT NULL DEFAULT 'post',
item bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY doctermitem (doc, term, item)) $charset_collate";
dbDelta( $sql );
$sql = "SHOW INDEX FROM $relevanssi_table";
$indices = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery
$terms_exists = false;
$relevanssi_term_reverse_idx_exists = false;
$docs_exists = false;
$typeitem_exists = false;
$doctermitem_exists = false;
foreach ( $indices as $index ) {
if ( 'terms' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$terms_exists = true;
}
if ( 'relevanssi_term_reverse_idx' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$relevanssi_term_reverse_idx_exists = true;
}
if ( 'docs' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$docs_exists = true;
}
if ( 'typeitem' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$typeitem_exists = true;
}
if ( 'doctermitem' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$doctermitem_exists = true;
}
}
if ( ! $terms_exists ) {
$sql = "CREATE INDEX terms ON $relevanssi_table (term(20))";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
}
if ( ! $relevanssi_term_reverse_idx_exists ) {
$sql = "CREATE INDEX relevanssi_term_reverse_idx ON $relevanssi_table (term_reverse(10))";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
}
if ( ! $typeitem_exists ) {
$sql = "CREATE INDEX typeitem ON $relevanssi_table (type(190), item)";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
}
if ( $doctermitem_exists ) {
$sql = "DROP INDEX doctermitem ON $relevanssi_table";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
}
if ( $docs_exists ) { // This index was removed in 4.9.2 / 2.11.2.
$sql = "DROP INDEX docs ON $relevanssi_table";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
}
$sql = 'CREATE TABLE ' . $relevanssi_stopword_table . " (stopword varchar(50) $charset_collate_bin_column NOT NULL,
PRIMARY KEY stopword (stopword)) $charset_collate;";
dbDelta( $sql );
$sql = 'CREATE TABLE ' . $relevanssi_log_table . " (id bigint(9) NOT NULL AUTO_INCREMENT,
query varchar(200) NOT NULL,
hits mediumint(9) NOT NULL DEFAULT '0',
time timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
user_id bigint(20) NOT NULL DEFAULT '0',
ip varchar(40) NOT NULL DEFAULT '',
PRIMARY KEY id (id)) $charset_collate;";
dbDelta( $sql );
$sql = "SHOW INDEX FROM $relevanssi_log_table";
$indices = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
$query_exists = false;
$id_exists = false;
foreach ( $indices as $index ) {
if ( 'query' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$query_exists = true;
}
if ( 'id' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
$id_exists = true;
}
}
if ( ! $query_exists ) {
$sql = "CREATE INDEX query ON $relevanssi_log_table (query(190))";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
}
if ( $id_exists ) {
$sql = "DROP INDEX id ON $relevanssi_log_table";
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
}
/**
* Allows adding database tables.
*
* An action hook that runs in the create tables process if the database
* version in the options doesn't match the database version in the
* code.
*
* @param string $charset_collate The collation.
*/
do_action( 'relevanssi_create_tables', $charset_collate );
update_option( 'relevanssi_db_version', $relevanssi_db_version );
$stopwords = relevanssi_fetch_stopwords();
if ( empty( $stopwords ) ) {
relevanssi_populate_stopwords();
}
}
/**
* Prints out the action links on the Plugins page.
*
* Hooked on to the 'plugin_action_links_' filter hook.
*
* @param array $links Action links for Relevanssi.
*
* @return array Updated action links.
*/
function relevanssi_action_links( $links ) {
$root = 'relevanssi';
if ( RELEVANSSI_PREMIUM ) {
$root = 'relevanssi-premium';
}
$relevanssi_links = array(
'<a href="' . admin_url( 'options-general.php?page=' . $root . '/relevanssi.php' ) . '">' . __( 'Settings', 'relevanssi' ) . '</a>',
);
if ( ! RELEVANSSI_PREMIUM ) {
$relevanssi_links[] = '<a href="https://www.relevanssi.com/buy-premium/">' . __( 'Go Premium!', 'relevanssi' ) . '</a>';
}
return array_merge( $relevanssi_links, $links );
}
/**
* Disables Relevanssi in REST API searches.
*
* Relevanssi doesn't work in the REST API context, so disable and allow the
* default search to work.
*/
function relevanssi_rest_api_disable() {
remove_filter( 'posts_request', 'relevanssi_prevent_default_request' );
remove_filter( 'the_posts', 'relevanssi_query', 99 );
}
/**
* Checks if a log export is requested.
*
* If the 'relevanssi_export' query variable is set, a log export has been
* requested and one will be provided by relevanssi_export_log(). The click
* tracking log export checks 'relevanssi_export_clicks' and uses the function
* relevanssi_export_click_log().
*
* @see relevanssi_export_log
* @see relevanssi_export_click_log
*/
function relevanssi_export_log_check() {
if ( isset( $_REQUEST['relevanssi_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification, just checking the parameter exists.
relevanssi_export_log();
}
if ( isset( $_REQUEST['relevanssi_export_clicks'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification, just checking the parameter exists.
function_exists( 'relevanssi_export_click_log' ) && relevanssi_export_click_log();
}
}
/**
* Loads in the Relevanssi plugin compatibility code.
*/
function relevanssi_load_compatibility_code() {
class_exists( 'acf', false ) && require_once 'compatibility/acf.php';
class_exists( 'DGWT_WC_Ajax_Search', false ) && require_once 'compatibility/fibosearch.php';
class_exists( 'Jet_Smart_Filters', false ) && require_once 'compatibility/jetsmartfilters.php';
class_exists( 'MeprUpdateCtrl', false ) && MeprUpdateCtrl::is_activated() && require_once 'compatibility/memberpress.php';
class_exists( 'Obenland_Wp_Search_Suggest', false ) && require_once 'compatibility/wp-search-suggest.php';
class_exists( 'Polylang', false ) && require_once 'compatibility/polylang.php';
class_exists( 'RankMath', false ) && require_once 'compatibility/rankmath.php';
class_exists( 'WooCommerce', false ) && require_once 'compatibility/woocommerce.php';
defined( 'AIOSEO_DIR' ) && require_once 'compatibility/aioseo.php';
defined( 'AVADA_VERSION' ) && require_once 'compatibility/avada.php';
defined( 'BRICKS_VERSION' ) && require_once 'compatibility/bricks.php';
defined( 'CT_VERSION' ) && require_once 'compatibility/oxygen.php';
defined( 'ELEMENTOR_VERSION' ) && require_once 'compatibility/elementor.php';
defined( 'GROUPS_CORE_VERSION' ) && require_once 'compatibility/groups.php';
defined( 'NINJA_TABLES_VERSION' ) && require_once 'compatibility/ninjatables.php';
defined( 'PRLI_PLUGIN_NAME' ) && require_once 'compatibility/pretty-links.php';
defined( 'WPM_PRODUCT_GTIN_WC_VERSION' ) && require_once 'compatibility/product-gtin-ean-upc-isbn-for-woocommerce.php';
defined( 'SIMPLE_WP_MEMBERSHIP_VER' ) && require_once 'compatibility/simplemembership.php';
defined( 'THE_SEO_FRAMEWORK_VERSION' ) && require_once 'compatibility/seoframework.php';
defined( 'WPFD_VERSION' ) && require_once 'compatibility/wp-file-download.php';
defined( 'WPMEM_VERSION' ) && require_once 'compatibility/wp-members.php';
defined( 'WPSEO_FILE' ) && require_once 'compatibility/yoast-seo.php';
function_exists( 'do_blocks' ) && require_once 'compatibility/gutenberg.php';
function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) && require_once 'compatibility/wpml.php';
function_exists( 'members_content_permissions_enabled' ) && require_once 'compatibility/members.php';
function_exists( 'pmpro_has_membership_access' ) && require_once 'compatibility/paidmembershippro.php';
function_exists( 'rcp_user_can_access' ) && require_once 'compatibility/restrictcontentpro.php';
function_exists( 'seopress_get_toggle_titles_option' ) && '1' === seopress_get_toggle_titles_option() && require_once 'compatibility/seopress.php';
function_exists( 'wp_jv_prg_user_can_see_a_post' ) && require_once 'compatibility/wpjvpostreadinggroups.php';
// phpcs:disable WordPress.NamingConventions.ValidVariableName
global $userAccessManager;
isset( $userAccessManager ) && require_once 'compatibility/useraccessmanager.php';
// phpcs:enable WordPress.NamingConventions.ValidVariableName
// Always required, the functions check if TablePress is active.
require_once 'compatibility/tablepress.php';
}

View File

@@ -1,148 +0,0 @@
<?php
/**
* /lib/install.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Installs Relevanssi on a new plugin if Relevanssi is network active.
*
* Hooks on to 'wpmu_new_blog' and 'wp_insert_site' action hooks and runs
* '_relevanssi_install' on the new blog.
*
* @param int|object $blog Either the blog ID (if 'wpmu_new_blog') or new site
* object (if 'wp_insert_site').
*/
function relevanssi_new_blog( $blog ) {
if ( is_int( $blog ) ) {
$blog_id = $blog;
} else {
$blog_id = $blog->id;
}
if ( is_plugin_active_for_network( 'relevanssi-premium/relevanssi.php' ) || is_plugin_active_for_network( 'relevanssi/relevanssi.php' ) ) {
switch_to_blog( $blog_id );
_relevanssi_install();
restore_current_blog();
}
}
/**
* Runs _relevanssi_install() on one blog or for the whole network.
*
* If Relevanssi is network active, this installs Relevanssi on all blogs in the
* network, running the _relevanssi_install() function.
*
* @param boolean $network_wide If true, install on all sites. Default false.
*/
function relevanssi_install( $network_wide = false ) {
if ( $network_wide ) {
$args = array(
'spam' => 0,
'deleted' => 0,
'archived' => 0,
'fields' => 'ids',
);
$blog_ids = get_sites( $args );
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );
_relevanssi_install();
restore_current_blog();
}
} else {
_relevanssi_install();
}
}
/**
* Installs Relevanssi on the blog.
*
* Adds Relevanssi options and sets their default values and generates the
* database tables.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function _relevanssi_install() {
global $relevanssi_variables;
add_option( 'relevanssi_admin_search', 'off' );
add_option( 'relevanssi_bg_col', '#ffaf75' );
add_option( 'relevanssi_cat', '0' );
add_option( 'relevanssi_class', 'relevanssi-query-term' );
add_option( 'relevanssi_comment_boost', $relevanssi_variables['comment_boost_default'] );
add_option( 'relevanssi_content_boost', $relevanssi_variables['content_boost_default'] );
add_option( 'relevanssi_css', 'text-decoration: underline; color: #ff0000' );
add_option( 'relevanssi_db_version', '0' );
add_option( 'relevanssi_debugging_mode', 'off' );
add_option( 'relevanssi_default_orderby', 'relevance' );
add_option( 'relevanssi_disable_or_fallback', 'off' );
add_option( 'relevanssi_exact_match_bonus', 'on' );
add_option( 'relevanssi_excat', '0' );
add_option( 'relevanssi_excerpt_allowable_tags', '' );
add_option( 'relevanssi_excerpt_custom_fields', 'off' );
add_option( 'relevanssi_excerpt_length', '30' );
add_option( 'relevanssi_excerpt_type', 'words' );
add_option( 'relevanssi_excerpts', 'on' );
add_option( 'relevanssi_exclude_posts', '' );
add_option( 'relevanssi_expand_highlights', 'off' );
add_option( 'relevanssi_expand_shortcodes', 'on' );
add_option( 'relevanssi_extag', '0' );
add_option( 'relevanssi_fuzzy', 'always' );
add_option( 'relevanssi_highlight', 'strong' );
add_option( 'relevanssi_highlight_comments', 'off' );
add_option( 'relevanssi_highlight_docs', 'off' );
add_option( 'relevanssi_hilite_title', '' );
add_option( 'relevanssi_implicit_operator', 'OR' );
add_option( 'relevanssi_index_author', '' );
add_option( 'relevanssi_index_comments', 'none' );
add_option( 'relevanssi_index_excerpt', 'off' );
add_option( 'relevanssi_index_fields', '' );
add_option( 'relevanssi_index_image_files', 'on' );
add_option( 'relevanssi_index_post_types', array( 'post', 'page' ) );
add_option( 'relevanssi_index_taxonomies_list', array() );
add_option( 'relevanssi_indexed', '' );
add_option( 'relevanssi_log_queries', 'off' );
add_option( 'relevanssi_log_queries_with_ip', 'off' );
add_option( 'relevanssi_min_word_length', '3' );
add_option( 'relevanssi_omit_from_logs', '' );
add_option( 'relevanssi_polylang_all_languages', 'off' );
add_option(
'relevanssi_punctuation',
array(
'quotes' => 'replace',
'hyphens' => 'replace',
'ampersands' => 'replace',
)
);
add_option( 'relevanssi_respect_exclude', 'on' );
add_option( 'relevanssi_seo_noindex', 'on' );
add_option( 'relevanssi_show_matches', '' );
add_option( 'relevanssi_show_matches_text', '(Search hits: %body% in body, %title% in title, %categories% in categories, %tags% in tags, %taxonomies% in other taxonomies, %comments% in comments. Score: %score%)' );
add_option( 'relevanssi_stopwords', array() );
add_option( 'relevanssi_synonyms', array() );
add_option( 'relevanssi_throttle', 'on' );
add_option( 'relevanssi_throttle_limit', '500' );
add_option( 'relevanssi_title_boost', $relevanssi_variables['title_boost_default'] );
add_option( 'relevanssi_txt_col', '#ff0000' );
add_option( 'relevanssi_wpml_only_current', 'on' );
if ( function_exists( 'relevanssi_premium_install' ) ) {
// Do some Relevanssi Premium additions.
relevanssi_premium_install();
}
/**
* Runs after Relevanssi options are added in the installation process.
*
* This action hook can be used to adjust the options to set your own default
* settings, for example.
*/
do_action( 'relevanssi_update_options' );
relevanssi_create_database_tables( $relevanssi_variables['database_version'] );
}

View File

@@ -1,523 +0,0 @@
<?php
/**
* /lib/interface.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Controls the Relevanssi settings page.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_options() {
global $relevanssi_variables;
$options_txt = __( 'Relevanssi Search Options', 'relevanssi' );
if ( RELEVANSSI_PREMIUM ) {
$options_txt = __( 'Relevanssi Premium Search Options', 'relevanssi' );
}
printf( "<div class='wrap'><h2>%s</h2>", esc_html( $options_txt ) );
if ( ! empty( $_REQUEST ) ) {
if ( isset( $_REQUEST['submit'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
update_relevanssi_options( $_REQUEST );
}
if ( isset( $_REQUEST['import_options'] ) ) {
if ( function_exists( 'relevanssi_import_options' ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
$options = $_REQUEST['relevanssi_settings'];
relevanssi_import_options( $options );
}
}
if ( isset( $_REQUEST['search'] ) ) {
relevanssi_search( $_REQUEST['q'] );
}
if ( isset( $_REQUEST['dowhat'] ) ) {
if ( 'add_stopword' === $_REQUEST['dowhat'] ) {
if ( isset( $_REQUEST['term'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_add_stopword( $_REQUEST['term'] );
}
if ( isset( $_REQUEST['body_term'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_add_body_stopword( $_REQUEST['body_term'] );
}
}
}
if ( isset( $_REQUEST['addstopword'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_add_stopword( $_REQUEST['addstopword'] );
}
if ( isset( $_REQUEST['removestopword'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_remove_stopword( $_REQUEST['removestopword'] );
}
if ( isset( $_REQUEST['removeallstopwords'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_remove_all_stopwords();
}
if ( isset( $_REQUEST['repopulatestopwords'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
$verbose = true;
relevanssi_populate_stopwords( $verbose );
}
if ( isset( $_REQUEST['addbodystopword'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_add_body_stopword( $_REQUEST['addbodystopword'] );
}
if ( isset( $_REQUEST['removebodystopword'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_remove_body_stopword( $_REQUEST['removebodystopword'] );
}
if ( isset( $_REQUEST['removeallbodystopwords'] ) ) {
check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
relevanssi_remove_all_body_stopwords();
}
if ( isset( $_REQUEST['update_counts'] ) ) {
check_admin_referer( 'update_counts' );
relevanssi_update_counts();
}
}
relevanssi_options_form();
echo "<div style='clear:both'></div></div>";
}
/**
* Prints out the 'Admin search' page.
*/
function relevanssi_admin_search_page() {
global $relevanssi_variables;
$options_txt = __( 'Admin Search', 'relevanssi' );
printf( "<div class='wrap'><h2>%s</h2>", esc_html( $options_txt ) );
require_once dirname( $relevanssi_variables['file'] ) . '/lib/tabs/search-page.php';
relevanssi_search_tab();
}
/**
* Truncates the Relevanssi logs.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param boolean $verbose If true, prints out a notice. Default true.
*
* @return boolean True if success, false if failure.
*/
function relevanssi_truncate_logs( $verbose = true ) {
global $wpdb, $relevanssi_variables;
$result = $wpdb->query( 'TRUNCATE ' . $relevanssi_variables['log_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( isset( $relevanssi_variables['tracking_table'] ) ) {
$tracking_result = $wpdb->query( 'TRUNCATE ' . $relevanssi_variables['tracking_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$results = $result && $tracking_result;
}
if ( $verbose ) {
if ( false !== $result ) {
printf( "<div id='relevanssi-warning' class='updated fade'>%s</div>", esc_html__( 'Logs clear!', 'relevanssi' ) );
} else {
printf( "<div id='relevanssi-warning' class='updated fade'>%s</div>", esc_html__( 'Clearing the logs failed.', 'relevanssi' ) );
}
}
return $result;
}
/**
* Prints out the Relevanssi options form.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_options_form() {
global $relevanssi_variables;
echo "<div class='postbox-container'>";
echo "<form method='post'>";
wp_nonce_field( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
$display_save_button = true;
$active_tab = 'overview';
if ( isset( $_REQUEST['tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$active_tab = $_REQUEST['tab']; // phpcs:ignore WordPress.Security.NonceVerification
}
if ( 'stopwords' === $active_tab ) {
$display_save_button = false;
}
printf( "<input type='hidden' name='tab' value='%s' />", esc_attr( $active_tab ) );
$this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
$tabs = array(
array(
'slug' => 'overview',
'name' => __( 'Overview', 'relevanssi' ),
'require' => 'tabs/overview-tab.php',
'callback' => 'relevanssi_overview_tab',
'save' => 'premium',
),
array(
'slug' => 'indexing',
'name' => __( 'Indexing', 'relevanssi' ),
'require' => 'tabs/indexing-tab.php',
'callback' => 'relevanssi_indexing_tab',
'save' => true,
),
array(
'slug' => 'attachments',
'name' => __( 'Attachments', 'relevanssi' ),
'require' => 'tabs/attachments-tab.php',
'callback' => 'relevanssi_attachments_tab',
'save' => false,
),
array(
'slug' => 'searching',
'name' => __( 'Searching', 'relevanssi' ),
'require' => 'tabs/searching-tab.php',
'callback' => 'relevanssi_searching_tab',
'save' => true,
),
array(
'slug' => 'logging',
'name' => __( 'Logging', 'relevanssi' ),
'require' => 'tabs/logging-tab.php',
'callback' => 'relevanssi_logging_tab',
'save' => true,
),
array(
'slug' => 'excerpts',
'name' => __( 'Excerpts and highlights', 'relevanssi' ),
'require' => 'tabs/excerpts-tab.php',
'callback' => 'relevanssi_excerpts_tab',
'save' => true,
),
array(
'slug' => 'synonyms',
'name' => __( 'Synonyms', 'relevanssi' ),
'require' => 'tabs/synonyms-tab.php',
'callback' => 'relevanssi_synonyms_tab',
'save' => true,
),
array(
'slug' => 'stopwords',
'name' => __( 'Stopwords', 'relevanssi' ),
'require' => 'tabs/stopwords-tab.php',
'callback' => 'relevanssi_stopwords_tab',
'save' => true,
),
array(
'slug' => 'redirects',
'name' => __( 'Redirects', 'relevanssi' ),
'require' => 'tabs/redirects-tab.php',
'callback' => 'relevanssi_redirects_tab',
'save' => false,
),
array(
'slug' => 'debugging',
'name' => __( 'Debugging', 'relevanssi' ),
'require' => 'tabs/debugging-tab.php',
'callback' => 'relevanssi_debugging_tab',
'save' => true,
),
);
/**
* Allows adding new tabs to the Relevanssi menu.
*
* @param array $tabs An array of arrays defining the tabs.
*
* @return array Filtered tab array.
*/
$tabs = apply_filters( 'relevanssi_tabs', $tabs );
?>
<h2 class="nav-tab-wrapper">
<?php
array_walk(
$tabs,
function( $tab ) use ( $this_page, $active_tab ) {
?>
<a href="<?php echo esc_attr( $this_page ); ?>&amp;tab=<?php echo esc_attr( $tab['slug'] ); ?>"
class="nav-tab <?php echo esc_attr( $tab['slug'] === $active_tab ? 'nav-tab-active' : '' ); ?>">
<?php echo esc_html( $tab['name'] ); ?></a>
<?php
}
);
?>
</h2>
<?php
$current_tab = $tabs[ array_search( $active_tab, wp_list_pluck( $tabs, 'slug' ), true ) ];
if ( ! $current_tab['save'] || ( ! RELEVANSSI_PREMIUM && 'premium' === $current_tab['save'] ) ) {
$display_save_button = false;
}
if ( $current_tab['require'] ) {
require_once $current_tab['require'];
}
call_user_func( $current_tab['callback'] );
if ( $display_save_button ) :
?>
<input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' />
<?php endif; ?>
</form>
</div>
<?php
}
/**
* Adds admin scripts to Relevanssi pages.
*
* Hooks to the 'admin_enqueue_scripts' action hook.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param string $hook The hook suffix for the current admin page.
*/
function relevanssi_add_admin_scripts( $hook ) {
global $relevanssi_variables;
$plugin_dir_url = plugin_dir_url( $relevanssi_variables['file'] );
// Only enqueue on Relevanssi pages.
$acceptable_hooks = array(
'toplevel_page_relevanssi-premium/relevanssi',
'settings_page_relevanssi-premium/relevanssi',
'dashboard_page_relevanssi-premium/relevanssi',
'toplevel_page_relevanssi/relevanssi',
'settings_page_relevanssi/relevanssi',
'dashboard_page_relevanssi/relevanssi',
'dashboard_page_relevanssi_admin_search',
);
/**
* Filters the hooks where Relevanssi scripts are enqueued.
*
* By default Relevanssi only enqueues the Relevanssi admin javascript on
* specific admin page hooks to avoid polluting the admin. If you want to
* move things around, this means the javascript bits won't work. You can
* introduce new hooks with this filter hook.
*
* @param array An array of page hook strings where Relevanssi scripts are
* added.
*/
if ( ! in_array( $hook, apply_filters( 'relevanssi_acceptable_hooks', $acceptable_hooks ), true ) ) {
return;
}
wp_enqueue_style( 'wp-color-picker' );
wp_enqueue_script( 'relevanssi_admin_js', $plugin_dir_url . 'lib/admin_scripts.js', array( 'wp-color-picker' ), $relevanssi_variables['plugin_version'], true );
if ( ! RELEVANSSI_PREMIUM ) {
wp_enqueue_script( 'relevanssi_admin_js_free', $plugin_dir_url . 'lib/admin_scripts_free.js', array( 'relevanssi_admin_js' ), $relevanssi_variables['plugin_version'], true );
}
if ( RELEVANSSI_PREMIUM ) {
wp_enqueue_script( 'relevanssi_admin_js_premium', $plugin_dir_url . 'premium/admin_scripts_premium.js', array( 'relevanssi_admin_js' ), $relevanssi_variables['plugin_version'], true );
}
wp_enqueue_style( 'relevanssi_admin_css', $plugin_dir_url . 'lib/admin_styles.css', array(), $relevanssi_variables['plugin_version'] );
if ( 'dashboard_page_relevanssi' === substr( $hook, 0, strlen( 'dashboard_page_relevanssi' ) ) ) {
wp_enqueue_script( 'chartjs', 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.min.js', array(), '3.3.2', false );
}
$localizations = array(
'confirm' => __( 'Click OK to copy Relevanssi options to all subsites', 'relevanssi' ),
'confirm_stopwords' => __( 'Are you sure you want to remove all stopwords?', 'relevanssi' ),
'confirm_delete_query' => __( 'Are you sure you want to delete the query?', 'relevanssi' ),
'truncating_index' => __( 'Wiping out the index...', 'relevanssi' ),
'done' => __( 'Done.', 'relevanssi' ),
'indexing_users' => __( 'Indexing users...', 'relevanssi' ),
'indexing_taxonomies' => __( 'Indexing the following taxonomies:', 'relevanssi' ),
'indexing_attachments' => __( 'Indexing attachments...', 'relevanssi' ),
'counting_posts' => __( 'Counting posts...', 'relevanssi' ),
'counting_terms' => __( 'Counting taxonomy terms...', 'relevanssi' ),
'counting_users' => __( 'Counting users...', 'relevanssi' ),
'counting_attachments' => __( 'Counting attachments...', 'relevanssi' ),
'posts_found' => __( 'posts found.', 'relevanssi' ),
'terms_found' => __( 'taxonomy terms found.', 'relevanssi' ),
'users_found' => __( 'users found.', 'relevanssi' ),
'attachments_found' => __( 'attachments found.', 'relevanssi' ),
'taxonomy_disabled' => __( 'Taxonomy term indexing is disabled.', 'relevanssi' ),
'user_disabled' => __( 'User indexing is disabled.', 'relevanssi' ),
'indexing_complete' => __( 'Indexing complete.', 'relevanssi' ),
'excluded_posts' => __( 'posts excluded.', 'relevanssi' ),
'options_changed' => __( 'Settings have changed, please save the options before indexing.', 'relevanssi' ),
'reload_state' => __( 'Reload the page to refresh the state of the index.', 'relevanssi' ),
'pdf_reset_confirm' => __( 'Are you sure you want to delete all attachment content from the index?', 'relevanssi' ),
'pdf_reset_done' => __( 'Relevanssi attachment data wiped clean.', 'relevanssi' ),
'pdf_reset_problems' => __( 'There were problems wiping the Relevanssi attachment data clean.', 'relevanssi' ),
'hour' => __( 'hour', 'relevanssi' ),
'hours' => __( 'hours', 'relevanssi' ),
'about' => __( 'about', 'relevanssi' ),
'sixty_min' => __( 'about an hour', 'relevanssi' ),
'ninety_min' => __( 'about an hour and a half', 'relevanssi' ),
'minute' => __( 'minute', 'relevanssi' ),
'minutes' => __( 'minutes', 'relevanssi' ),
'underminute' => __( 'less than a minute', 'relevanssi' ),
'notimeremaining' => __( "we're done!", 'relevanssi' ),
);
wp_localize_script( 'relevanssi_admin_js', 'relevanssi', $localizations );
$nonce = array(
'indexing_nonce' => wp_create_nonce( 'relevanssi_indexing_nonce' ),
'searching_nonce' => wp_create_nonce( 'relevanssi_admin_search_nonce' ),
);
if ( ! RELEVANSSI_PREMIUM ) {
wp_localize_script( 'relevanssi_admin_js', 'nonce', $nonce );
}
/**
* Sets the indexing limit, ie. how many posts are indexed at once.
*
* Relevanssi starts by indexing this many posts at once. If the process
* goes fast enough, Relevanssi will then increase the limit and if the
* process is slow, the limit will be decreased. If necessary, you can
* use the relevanssi_indexing_adjust filter hook to disable that
* adjustment.
*
* @param int The indexing limit, default 10.
*/
$indexing_limit = apply_filters( 'relevanssi_indexing_limit', 10 );
/**
* Sets the indexing adjustment.
*
* Relevanssi will adjust the number of posts indexed at once to speed
* up the process if it goes fast and to slow down, if the posts are
* slow to index. You can use this filter to stop that behaviour, making
* Relevanssi index posts at constant pace. That's generally slower, but
* more reliable.
*
* @param boolean Should the limit be adjusted, default true.
*/
$indexing_adjust = apply_filters( 'relevanssi_indexing_adjust', true );
wp_localize_script(
'relevanssi_admin_js',
'relevanssi_params',
array(
'indexing_limit' => $indexing_limit,
'indexing_adjust' => $indexing_adjust,
)
);
}
/**
* Prints out the form fields for tag and category weights.
*/
function relevanssi_form_tag_weight() {
$taxonomy_weights = get_option( 'relevanssi_post_type_weights' );
$tag_value = 1;
if ( isset( $taxonomy_weights['post_tag'] ) ) {
$tag_value = $taxonomy_weights['post_tag'];
}
$category_value = 1;
if ( isset( $taxonomy_weights['category'] ) ) {
$category_value = $taxonomy_weights['category'];
}
?>
<tr>
<td>
<?php esc_html_e( 'Tag weight', 'relevanssi' ); ?>
</td>
<td class="col-2">
<input type='text' id='relevanssi_weight_post_tag' name='relevanssi_weight_post_tag' size='4' value='<?php echo esc_attr( $tag_value ); ?>' />
</td>
</tr>
<tr>
<td>
<?php esc_html_e( 'Category weight', 'relevanssi' ); ?>
</td>
<td class="col-2">
<input type='text' id='relevanssi_weight_category' name='relevanssi_weight_category' size='4' value='<?php echo esc_attr( $category_value ); ?>' />
</td>
</tr>
<?php
}
/**
* Creates a line chart.
*
* @param array $labels An array of labels for the line chart. These will be
* wrapped in apostrophes.
* @param array $datasets An array of (label, dataset) pairs.
*/
function relevanssi_create_line_chart( array $labels, array $datasets ) {
$labels = implode( ', ', array_map( 'relevanssi_add_apostrophes', $labels ) );
$datasets_array = array();
$bg_colors = array(
"'rgba(255, 99, 132, 0.2)'",
"'rgba(0, 175, 255, 0.2)'",
);
$border_colors = array(
"'rgba(255, 99, 132, 1)'",
"'rgba(0, 175, 255, 1)'",
);
foreach ( $datasets as $label => $values ) {
$values = implode( ', ', $values );
$bg_color = array_shift( $bg_colors );
$border_color = array_shift( $border_colors );
$datasets_array[] = <<< EOJSON
{
label: "$label",
data: [ $values ],
backgroundColor: [ $bg_color ],
borderColor: [ $border_color ],
borderWidth: 2,
fill: {
target: 'origin',
below: $border_color,
},
pointRadius: 1,
cubicInterpolationMode: 'monotone'
}
EOJSON;
}
?>
<canvas id="search_chart" height="100"></canvas>
<script>
var ctx = document.getElementById('search_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [<?php echo $labels; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>],
datasets: [<?php echo implode( ",\n", $datasets_array ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>],
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
<?php
}

View File

@@ -1,366 +0,0 @@
<?php
/**
* /lib/log.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Adds the search query to the log.
*
* Logs the search query, trying to avoid bots.
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The global Relevanssi variables, used for database table names.
*
* @param string $query The search query.
* @param int $hits The number of hits found.
*
* @return boolean True if logged, false if not logged.
*/
function relevanssi_update_log( $query, $hits ) {
if ( empty( $query ) ) {
return false;
}
/**
* Filters the current user for logs.
*
* The current user is checked before logging a query to omit particular users.
* You can use this filter to filter out the user.
*
* @param WP_User The current user object.
*/
$user = apply_filters( 'relevanssi_log_get_user', wp_get_current_user() );
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if ( ! relevanssi_is_ok_to_log( $user ) ) {
return false;
}
$ip = '';
if ( 'on' === get_option( 'relevanssi_log_queries_with_ip' ) ) {
/**
* Filters the IP address of the searcher.
*
* Relevanssi may store the IP address of the searches in the logs. If the
* setting is enabled, this filter can be used to filter out the IP address
* before the log entry is made.
*
* Do note that storing the IP address may be illegal or get you in GDPR
* trouble.
*
* @param string $ip The IP address, from $_SERVER['REMOTE_ADDR'].
*/
$ip = apply_filters( 'relevanssi_remote_addr', $_SERVER['REMOTE_ADDR'] );
}
/**
* Filters whether a query should be logged or not.
*
* This filter can used to determine whether a query should be logged or not.
*
* @param boolean $ok_to_log Can the query be logged.
* @param string $query The actual query string.
* @param int $hits The number of hits found.
* @param string $user_agent The user agent that made the search.
* @param string $ip The IP address the search came from (or empty).
*/
$ok_to_log = apply_filters( 'relevanssi_ok_to_log', true, $query, $hits, $user_agent, $ip );
if ( $ok_to_log ) {
global $wpdb, $relevanssi_variables;
$wpdb->query(
$wpdb->prepare(
'INSERT INTO ' . $relevanssi_variables['log_table'] . ' (query, hits, user_id, ip, time) VALUES (%s, %d, %d, %s, NOW())', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$query,
intval( $hits ),
$user->ID,
$ip
)
);
return true;
}
return false;
}
/**
* Trims Relevanssi log table.
*
* Trims Relevanssi log table, using the day interval setting from 'relevanssi_trim_logs'.
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The global Relevanssi variables, used for database table names.
*
* @return int|bool Number of rows deleted, or false on error.
*/
function relevanssi_trim_logs() {
global $wpdb, $relevanssi_variables;
$interval = intval( get_option( 'relevanssi_trim_logs' ) );
return $wpdb->query(
$wpdb->prepare(
'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE time < TIMESTAMP(DATE_SUB(NOW(), INTERVAL %d DAY))', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$interval
)
);
}
/**
* Generates the user export data.
*
* @since 4.0.10
*
* @param int $user_id The user ID to export.
* @param int $page Paging to avoid time outs.
*
* @return array Two-item array: 'done' is a Boolean that tells if the exporter is
* done, 'data' contains the actual data.
*/
function relevanssi_export_log_data( $user_id, $page ) {
global $wpdb, $relevanssi_variables;
$page = (int) $page;
if ( $page < 1 ) {
$page = 1;
}
$limit = 500;
$offset = $limit * ( $page - 1 );
$log_data = $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d OFFSET %d', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$user_id,
$limit,
$offset
)
);
$export_items = array();
foreach ( $log_data as $row ) {
$time = $row->time;
$query = $row->query;
$id = $row->id;
$ip = $row->ip;
$hits = $row->hits;
$item_id = "relevanssi_logged_search-{$id}";
$group_id = 'relevanssi_logged_searches';
$group_label = __( 'Logged searches', 'relevanssi' );
$data = array(
array(
'name' => __( 'Time', 'relevanssi' ),
'value' => $time,
),
array(
'name' => __( 'Query', 'relevanssi' ),
'value' => $query,
),
array(
'name' => __( 'Hits found', 'relevanssi' ),
'value' => $hits,
),
array(
'name' => __( 'IP address', 'relevanssi' ),
'value' => $ip,
),
);
$export_items[] = array(
'group_id' => $group_id,
'group_label' => $group_label,
'item_id' => $item_id,
'data' => $data,
);
}
$done = false;
if ( count( $log_data ) < $limit ) {
$done = true;
}
return array(
'done' => $done,
'data' => $export_items,
);
}
/**
* Erases the user log data.
*
* @since 4.0.10
*
* @param int $user_id The user ID to erase.
* @param int $page Paging to avoid time outs.
*
* @return array Four-item array: 'items_removed' is a Boolean that tells if
* something was removed, 'done' is a Boolean that tells if the eraser is done,
* 'items_retained' is always false, 'messages' is always an empty array.
*/
function relevanssi_erase_log_data( $user_id, $page ) {
global $wpdb, $relevanssi_variables;
$page = (int) $page;
if ( $page < 1 ) {
$page = 1;
}
$limit = 500;
$rows_removed = $wpdb->query(
$wpdb->prepare(
'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$user_id,
$limit
)
);
$done = false;
if ( $rows_removed < $limit ) {
$done = true;
}
$items_removed = false;
if ( $rows_removed > 0 ) {
$items_removed = true;
}
return array(
'items_removed' => $items_removed,
'items_retained' => false,
'messages' => array(),
'done' => $done,
);
}
/**
* Prints out the Relevanssi log as a CSV file.
*
* Exports the whole Relevanssi search log as a CSV file.
*
* @uses relevanssi_output_exported_log
*
* @since 2.2
*/
function relevanssi_export_log() {
global $wpdb, $relevanssi_variables;
$data = $wpdb->get_results( 'SELECT * FROM ' . $relevanssi_variables['log_table'], ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
relevanssi_output_exported_log(
'relevanssi_log.csv',
$data,
__( 'No search keywords logged.', 'relevanssi' )
);
}
/**
* Prints out the log.
*
* Does the exporting work for log exports.
*
* @param string $filename The filename to use.
* @param array $data The data to export.
* @param string $message The message to print if there is no data.
*/
function relevanssi_output_exported_log( string $filename, array $data, string $message ) {
$now = gmdate( 'D, d M Y H:i:s' );
header( 'Expires: Tue, 03 Jul 2001 06:00:00 GMT' );
header( 'Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate' );
header( "Last-Modified: {$now} GMT" );
header( 'Content-Type: application/force-download' );
header( 'Content-Type: application/octet-stream' );
header( 'Content-Type: application/download' );
header( "Content-Disposition: attachment;filename={$filename}" );
header( 'Content-Transfer-Encoding: binary' );
ob_start();
$df = fopen( 'php://output', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions
if ( empty( $data ) ) {
fputcsv( $df, array( $message ) );
die();
}
fputcsv( $df, array_keys( reset( $data ) ) );
foreach ( $data as $row ) {
fputcsv( $df, $row );
}
fclose( $df ); // phpcs:ignore WordPress.WP.AlternativeFunctions
echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
die();
}
/**
* Checks if logging the query is ok.
*
* Returns false if the user agent is on the blocked bots list or if the
* current user is on the relevanssi_omit_from_logs option list.
*
* @param WP_User $user The current user. If null, gets the value from
* wp_get_current_user().
*
* @return boolean True, if the user is not a bot or not on the omit list.
*/
function relevanssi_is_ok_to_log( $user = null ) : bool {
if ( relevanssi_user_agent_is_bot() ) {
return false;
}
if ( ! $user ) {
$user = wp_get_current_user();
}
if ( 0 !== $user->ID && get_option( 'relevanssi_omit_from_logs' ) ) {
$omit = explode( ',', get_option( 'relevanssi_omit_from_logs' ) );
$omit = array_map( 'trim', $omit );
if ( in_array( strval( $user->ID ), $omit, true ) ) {
return false;
}
if ( in_array( $user->user_login, $omit, true ) ) {
return false;
}
}
return true;
}
/**
* Deletes a query from log.
*
* @param string $query The query to delete.
*/
function relevanssi_delete_query_from_log( string $query ) {
global $wpdb, $relevanssi_variables;
$deleted = $wpdb->query(
$wpdb->prepare(
"DELETE FROM {$relevanssi_variables['log_table']} WHERE query = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
stripslashes( $query )
)
);
if ( $deleted ) {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"The query '%s' deleted from the log.",
'relevanssi'
),
esc_html( stripslashes( $query ) )
)
);
} else {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"Couldn't remove the query '%s' from the log.",
'relevanssi'
),
esc_html( stripslashes( $query ) )
)
);
}
}

View File

@@ -1,393 +0,0 @@
<?php
/**
* /lib/options.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Updates Relevanssi options.
*
* Checks the option values and updates the options. It's safe to use $request
* here, check_admin_referer() is done immediately before this function is
* called.
*
* @param array $request The request array from $_REQUEST.
*/
function update_relevanssi_options( array $request ) {
if ( 'indexing' === $request['tab'] ) {
relevanssi_turn_off_options(
$request,
array(
'relevanssi_expand_shortcodes',
'relevanssi_index_author',
'relevanssi_index_excerpt',
'relevanssi_index_image_files',
'relevanssi_seo_noindex',
)
);
relevanssi_update_intval( $request, 'relevanssi_min_word_length', true, 3 );
do_action( 'relevanssi_indexing_options', $request );
}
if ( 'searching' === $request['tab'] ) {
relevanssi_turn_off_options(
$request,
array(
'relevanssi_admin_search',
'relevanssi_disable_or_fallback',
'relevanssi_exact_match_bonus',
'relevanssi_polylang_all_languages',
'relevanssi_respect_exclude',
'relevanssi_throttle',
'relevanssi_wpml_only_current',
)
);
relevanssi_update_floatval( $request, 'relevanssi_content_boost', true, 1, true );
relevanssi_update_floatval( $request, 'relevanssi_title_boost', true, 1, true );
relevanssi_update_floatval( $request, 'relevanssi_comment_boost', true, 1, true );
}
if ( 'logging' === $request['tab'] ) {
relevanssi_turn_off_options(
$request,
array(
'relevanssi_log_queries',
'relevanssi_log_queries_with_ip',
)
);
}
if ( 'excerpts' === $request['tab'] ) {
relevanssi_turn_off_options(
$request,
array(
'relevanssi_excerpt_custom_fields',
'relevanssi_excerpts',
'relevanssi_expand_highlights',
'relevanssi_highlight_comments',
'relevanssi_highlight_docs',
'relevanssi_hilite_title',
'relevanssi_show_matches',
)
);
if ( isset( $request['relevanssi_show_matches_text'] ) ) {
$value = $request['relevanssi_show_matches_text'];
$value = str_replace( '"', "'", $value );
update_option( 'relevanssi_show_matches_text', $value );
}
relevanssi_update_intval( $request, 'relevanssi_excerpt_length', true, 10 );
if ( isset( $request['relevanssi_excerpt_allowable_tags'] ) ) {
$value = $request['relevanssi_excerpt_allowable_tags'];
$value = str_replace( array( ' ', '/' ), '', $value );
$value = implode( '>', array_unique( explode( '>', $value ) ) );
update_option( 'relevanssi_excerpt_allowable_tags', $value );
}
}
if ( 'debugging' === $request['tab'] ) {
relevanssi_turn_off_options( $request, array( 'relevanssi_debugging_mode' ) );
}
relevanssi_process_weights_and_indexing( $request );
relevanssi_process_synonym_options( $request );
relevanssi_process_punctuation_options( $request );
relevanssi_process_index_fields_option( $request );
relevanssi_process_trim_logs_option( $request );
relevanssi_process_cat_option( $request );
relevanssi_process_excat_option( $request );
// The values control the autoloading.
$options = array(
'relevanssi_admin_search' => false,
'relevanssi_bg_col' => true,
'relevanssi_class' => true,
'relevanssi_css' => true,
'relevanssi_debugging_mode' => true,
'relevanssi_default_orderby' => true,
'relevanssi_disable_or_fallback' => true,
'relevanssi_exact_match_bonus' => true,
'relevanssi_excerpt_custom_fields' => true,
'relevanssi_excerpt_type' => true,
'relevanssi_excerpts' => true,
'relevanssi_exclude_posts' => true,
'relevanssi_expand_shortcodes' => false,
'relevanssi_expand_highlights' => true,
'relevanssi_fuzzy' => true,
'relevanssi_highlight_comments' => true,
'relevanssi_highlight_docs' => true,
'relevanssi_highlight' => true,
'relevanssi_hilite_title' => true,
'relevanssi_implicit_operator' => true,
'relevanssi_index_author' => false,
'relevanssi_index_comments' => false,
'relevanssi_index_excerpt' => false,
'relevanssi_index_image_files' => true,
'relevanssi_log_queries_with_ip' => true,
'relevanssi_log_queries' => true,
'relevanssi_omit_from_logs' => true,
'relevanssi_polylang_all_languages' => true,
'relevanssi_respect_exclude' => true,
'relevanssi_show_matches' => true,
'relevanssi_throttle' => true,
'relevanssi_txt_col' => true,
'relevanssi_wpml_only_current' => true,
);
if ( isset( $request['relevanssi_exclude_posts'] ) ) {
$request['relevanssi_exclude_posts'] = trim( $request['relevanssi_exclude_posts'], ' ,' );
}
array_walk(
$options,
function( $autoload, $option ) use ( $request ) {
if ( isset( $request[ $option ] ) ) {
update_option( $option, $request[ $option ], $autoload );
}
}
);
if ( function_exists( 'relevanssi_update_premium_options' ) ) {
relevanssi_update_premium_options();
}
}
/**
* Fetches option values for variable name options.
*
* Goes through all options and picks up all options that have names that
* contain post types, taxonomies and so on.
*
* @param array $request The $request array.
*/
function relevanssi_process_weights_and_indexing( $request ) {
$post_type_weights = array();
$index_post_types = array();
$index_taxonomies_list = array();
$index_terms_list = array();
foreach ( $request as $key => $value ) {
if ( empty( $value ) ) {
$value = 0;
}
if ( 'relevanssi_weight_' === substr( $key, 0, strlen( 'relevanssi_weight_' ) ) ) {
$type = substr( $key, strlen( 'relevanssi_weight_' ) );
$post_type_weights[ $type ] = $value;
}
if ( 'relevanssi_taxonomy_weight_' === substr( $key, 0, strlen( 'relevanssi_taxonomy_weight_' ) ) ) {
$type = 'post_tagged_with_' . substr( $key, strlen( 'relevanssi_taxonomy_weight_' ) );
$post_type_weights[ $type ] = $value;
}
if ( 'relevanssi_term_weight_' === substr( $key, 0, strlen( 'relevanssi_term_weight_' ) ) ) {
$type = 'taxonomy_term_' . substr( $key, strlen( 'relevanssi_term_weight_' ) );
$post_type_weights[ $type ] = $value;
}
if ( 'relevanssi_index_type_' === substr( $key, 0, strlen( 'relevanssi_index_type_' ) ) ) {
$type = substr( $key, strlen( 'relevanssi_index_type_' ) );
if ( 'on' === $value ) {
$index_post_types[ $type ] = true;
}
}
if ( 'relevanssi_index_taxonomy_' === substr( $key, 0, strlen( 'relevanssi_index_taxonomy_' ) ) ) {
$type = substr( $key, strlen( 'relevanssi_index_taxonomy_' ) );
if ( 'on' === $value ) {
$index_taxonomies_list[ $type ] = true;
}
}
if ( 'relevanssi_index_terms_' === substr( $key, 0, strlen( 'relevanssi_index_terms_' ) ) ) {
$type = substr( $key, strlen( 'relevanssi_index_terms_' ) );
if ( 'on' === $value ) {
$index_terms_list[ $type ] = true;
}
}
}
if ( count( $post_type_weights ) > 0 ) {
$post_type_weights = array_map( 'relevanssi_sanitize_weights', $post_type_weights );
update_option( 'relevanssi_post_type_weights', $post_type_weights );
}
if ( count( $index_post_types ) > 0 ) {
update_option( 'relevanssi_index_post_types', array_keys( $index_post_types ) );
}
if ( 'indexing' === $request['tab'] ) {
update_option( 'relevanssi_index_taxonomies_list', array_keys( $index_taxonomies_list ), false );
if ( RELEVANSSI_PREMIUM ) {
update_option( 'relevanssi_index_terms', array_keys( $index_terms_list ), false );
}
}
}
/**
* Takes a value, converts it to float and if it's negative or zero, sets it
* to 1.
*
* @param mixed $weight The weight value, which can be anything user enters.
*
* @return float The float value of the weight.
*/
function relevanssi_sanitize_weights( $weight ) {
$weight = floatval( $weight );
if ( $weight <= 0 ) {
$weight = 1;
}
return $weight;
}
/**
* Compiles the punctuation settings from the request and updates the option.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_punctuation_options( array $request ) : bool {
$relevanssi_punct = array();
if ( isset( $request['relevanssi_punct_quotes'] ) ) {
$relevanssi_punct['quotes'] = $request['relevanssi_punct_quotes'];
}
if ( isset( $request['relevanssi_punct_hyphens'] ) ) {
$relevanssi_punct['hyphens'] = $request['relevanssi_punct_hyphens'];
}
if ( isset( $request['relevanssi_punct_ampersands'] ) ) {
$relevanssi_punct['ampersands'] = $request['relevanssi_punct_ampersands'];
}
if ( isset( $request['relevanssi_punct_decimals'] ) ) {
$relevanssi_punct['decimals'] = $request['relevanssi_punct_decimals'];
}
if ( ! empty( $relevanssi_punct ) ) {
return update_option( 'relevanssi_punctuation', $relevanssi_punct );
}
return false;
}
/**
* Updates the synonym option in the current language.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_synonym_options( array $request ) : bool {
if ( isset( $request['relevanssi_synonyms'] ) ) {
$linefeeds = array( "\r\n", "\n", "\r" );
$value = str_replace( $linefeeds, ';', $request['relevanssi_synonyms'] );
$value = stripslashes( $value );
$synonym_option = get_option( 'relevanssi_synonyms', array() );
$current_language = relevanssi_get_current_language();
$synonym_option[ $current_language ] = $value;
return update_option( 'relevanssi_synonyms', $synonym_option );
}
return false;
}
/**
* Updates the index_fields option in the current language.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_index_fields_option( array $request ) : bool {
if ( isset( $request['relevanssi_index_fields_select'] ) ) {
$fields_option = '';
if ( 'all' === $request['relevanssi_index_fields_select'] ) {
$fields_option = 'all';
}
if ( 'visible' === $request['relevanssi_index_fields_select'] ) {
$fields_option = 'visible';
}
if ( 'some' === $request['relevanssi_index_fields_select'] ) {
if ( isset( $request['relevanssi_index_fields'] ) ) {
$fields_option = rtrim( $request['relevanssi_index_fields'], " \t\n\r\0\x0B," );
}
}
return update_option( 'relevanssi_index_fields', $fields_option, false );
}
return false;
}
/**
* Updates the trim_logs option.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_trim_logs_option( array $request ) : bool {
if ( isset( $request['relevanssi_trim_logs'] ) ) {
$trim_logs = $request['relevanssi_trim_logs'];
if ( ! is_numeric( $trim_logs ) || $trim_logs < 0 ) {
$trim_logs = 0;
}
return update_option( 'relevanssi_trim_logs', $trim_logs );
}
return false;
}
/**
* Updates the cat option.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_cat_option( array $request ) : bool {
if ( isset( $request['relevanssi_cat'] ) ) {
if ( is_array( $request['relevanssi_cat'] ) ) {
return update_option(
'relevanssi_cat',
implode( ',', $request['relevanssi_cat'] )
);
}
} else {
if ( isset( $request['relevanssi_cat_active'] ) ) {
return update_option( 'relevanssi_cat', '' );
}
}
return false;
}
/**
* Updates the excat option.
*
* @param array $request The request array.
*
* @return boolean True, if update_option() succeeds, false otherwise.
*/
function relevanssi_process_excat_option( array $request ) : bool {
if ( isset( $request['relevanssi_excat'] ) ) {
if ( is_array( $request['relevanssi_excat'] ) ) {
$array_excats = $request['relevanssi_excat'];
$cat = get_option( 'relevanssi_cat' );
if ( $cat ) {
$array_cats = explode( ',', $cat );
$valid_excats = array();
foreach ( $array_excats as $excat ) {
if ( ! in_array( $excat, $array_cats, true ) ) {
$valid_excats[] = $excat;
}
}
} else {
// No category restrictions, so everything's good.
$valid_excats = $array_excats;
}
$csv_excats = implode( ',', $valid_excats );
return update_option( 'relevanssi_excat', $csv_excats );
}
} else {
if ( isset( $request['relevanssi_excat_active'] ) ) {
return update_option( 'relevanssi_excat', '' );
}
}
return false;
}

View File

@@ -1,290 +0,0 @@
<?php
/**
* /lib/phrases.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Extracts phrases from the search query.
*
* Finds all phrases wrapped in quotes (curly or straight) from the search
* query.
*
* @param string $query The search query.
*
* @return array An array of phrases (strings).
*/
function relevanssi_extract_phrases( string $query ) {
// iOS uses “” or „“ as the default quotes, so Relevanssi needs to
// understand those as well.
$normalized_query = str_replace( array( '”', '“', '„' ), '"', $query );
$pos = relevanssi_stripos( $normalized_query, '"' );
$phrases = array();
while ( false !== $pos ) {
if ( $pos + 2 > relevanssi_strlen( $normalized_query ) ) {
$pos = false;
continue;
}
$start = relevanssi_stripos( $normalized_query, '"', $pos );
$end = false;
if ( false !== $start ) {
$end = relevanssi_stripos( $normalized_query, '"', $start + 2 );
}
if ( false === $end ) {
// Just one " in the query.
$pos = $end;
continue;
}
$phrase = relevanssi_substr(
$normalized_query,
$start + 1,
$end - $start - 1
);
$phrase = trim( $phrase );
// Do not count single-word phrases as phrases.
if ( relevanssi_is_multiple_words( $phrase ) ) {
$phrases[] = $phrase;
}
$pos = $end + 1;
}
return $phrases;
}
/**
* Generates the MySQL code for restricting the search to phrase hits.
*
* This function uses relevanssi_extract_phrases() to figure out the phrases in
* the search query, then generates MySQL queries to restrict the search to the
* posts containing those phrases in the title, content, taxonomy terms or meta
* fields.
*
* @global array $relevanssi_variables The global Relevanssi variables.
*
* @param string $search_query The search query.
* @param string $operator The search operator (AND or OR).
*
* @return string $queries If not phrase hits are found, an empty string;
* otherwise MySQL queries to restrict the search.
*/
function relevanssi_recognize_phrases( $search_query, $operator = 'AND' ) {
global $relevanssi_variables;
$phrases = relevanssi_extract_phrases( $search_query );
$all_queries = array();
if ( 0 === count( $phrases ) ) {
return $all_queries;
}
$custom_fields = relevanssi_get_custom_fields();
$taxonomies = get_option( 'relevanssi_index_taxonomies_list', array() );
$excerpts = get_option( 'relevanssi_index_excerpt', 'off' );
$phrase_queries = array();
$queries = array();
if (
isset( $relevanssi_variables['phrase_targets'] ) &&
is_array( $relevanssi_variables['phrase_targets'] )
) {
$non_targeted_phrases = array();
foreach ( $phrases as $phrase ) {
if (
isset( $relevanssi_variables['phrase_targets'][ $phrase ] ) &&
function_exists( 'relevanssi_targeted_phrases' )
) {
$queries = relevanssi_targeted_phrases( $phrase );
} else {
$non_targeted_phrases[] = $phrase;
}
}
$phrases = $non_targeted_phrases;
}
$queries = array_merge(
$queries,
relevanssi_generate_phrase_queries(
$phrases,
$taxonomies,
$custom_fields,
$excerpts
)
);
$phrase_queries = array();
foreach ( $queries as $phrase => $p_queries ) {
$pq_array = array();
foreach ( $p_queries as $query ) {
$pq_array[] = "relevanssi.{$query['target']} IN {$query['query']}";
}
$p_queries = implode( ' OR ', $pq_array );
$all_queries[] = "($p_queries)";
$phrase_queries[ $phrase ] = $p_queries;
}
$operator = strtoupper( $operator );
if ( 'AND' !== $operator && 'OR' !== $operator ) {
$operator = 'AND';
}
if ( ! empty( $all_queries ) ) {
$all_queries = ' AND ( ' . implode( ' ' . $operator . ' ', $all_queries ) . ' ) ';
}
return array(
'and' => $all_queries,
'or' => $phrase_queries,
);
}
/**
* Generates the phrase queries from phrases.
*
* Takes in phrases and a bunch of parameters and generates the MySQL queries
* that restrict the main search query to only posts that have the phrase.
*
* @param array $phrases A list of phrases to handle.
* @param array $taxonomies An array of taxonomy names to use.
* @param array|string $custom_fields A list of custom field names to use,
* "visible", or "all".
* @param string $excerpts If 'on', include excerpts.
*
* @global object $wpdb The WordPress database interface.
*
* @return array An array of queries sorted by phrase.
*/
function relevanssi_generate_phrase_queries( array $phrases, array $taxonomies,
$custom_fields, string $excerpts ) : array {
global $wpdb;
$status = relevanssi_valid_status_array();
// Add "inherit" to the list of allowed statuses to include attachments.
if ( ! strstr( $status, 'inherit' ) ) {
$status .= ",'inherit'";
}
$phrase_queries = array();
foreach ( $phrases as $phrase ) {
$queries = array();
$phrase = $wpdb->esc_like( $phrase );
$phrase = str_replace( array( '', '', "'", '"', '”', '“', '“', '„', '´' ), '_', $phrase );
$title_phrase = $phrase;
$phrase = htmlspecialchars( $phrase );
/**
* Filters each phrase before it's passed through esc_sql() and used in
* the MySQL query. You can use this filter hook to for example run
* htmlentities() on the phrase in case your database needs that.
*
* @param string $phrase The phrase after quotes are replaced with a
* MySQL wild card and the phrase has been passed through esc_like() and
* htmlspecialchars().
*/
$phrase = esc_sql( apply_filters( 'relevanssi_phrase', $phrase ) );
$excerpt = '';
if ( 'on' === $excerpts ) {
$excerpt = "OR post_excerpt LIKE '%$phrase%'";
}
$query = "(SELECT ID FROM $wpdb->posts
WHERE (post_content LIKE '%$phrase%'
OR post_title LIKE '%$title_phrase%' $excerpt)
AND post_status IN ($status))";
$queries[] = array(
'query' => $query,
'target' => 'doc',
);
if ( $taxonomies ) {
$taxonomies_escaped = implode( "','", array_map( 'esc_sql', $taxonomies ) );
$taxonomies_sql = "AND s.taxonomy IN ('$taxonomies_escaped')";
$query = "(SELECT ID FROM
$wpdb->posts as p,
$wpdb->term_relationships as r,
$wpdb->term_taxonomy as s, $wpdb->terms as t
WHERE r.term_taxonomy_id = s.term_taxonomy_id
AND s.term_id = t.term_id AND p.ID = r.object_id
$taxonomies_sql
AND t.name LIKE '%$phrase%' AND p.post_status IN ($status))";
$queries[] = array(
'query' => $query,
'target' => 'doc',
);
}
if ( $custom_fields ) {
$keys = '';
if ( is_array( $custom_fields ) ) {
if ( ! in_array( '_relevanssi_pdf_content', $custom_fields, true ) ) {
array_push( $custom_fields, '_relevanssi_pdf_content' );
}
if ( strpos( implode( ' ', $custom_fields ), '%' ) ) {
// ACF repeater fields involved.
$custom_fields_regexp = str_replace( '%', '.+', implode( '|', $custom_fields ) );
$keys = "AND m.meta_key REGEXP ('$custom_fields_regexp')";
} else {
$custom_fields_escaped = implode(
"','",
array_map(
'esc_sql',
$custom_fields
)
);
$keys = "AND m.meta_key IN ('$custom_fields_escaped')";
}
}
if ( 'visible' === $custom_fields ) {
$keys = "AND (m.meta_key NOT LIKE '\_%' OR m.meta_key = '_relevanssi_pdf_content')";
}
$query = "(SELECT ID
FROM $wpdb->posts AS p, $wpdb->postmeta AS m
WHERE p.ID = m.post_id
$keys
AND m.meta_value LIKE '%$phrase%'
AND p.post_status IN ($status))";
$queries[] = array(
'query' => $query,
'target' => 'doc',
);
}
/**
* Filters the phrase queries.
*
* Relevanssi Premium uses this filter hook to add Premium-specific
* phrase queries.
*
* @param array $queries The MySQL queries for phrase matching.
* @param string $phrase The current phrase.
* @param string $status A string containing post statuses.
*
* @return array An array of phrase queries, where each query is an
* array that has the actual MySQL query in 'query' and the target
* column ('doc' or 'item') in the Relevanssi index table in 'target'.
*/
$queries = apply_filters( 'relevanssi_phrase_queries', $queries, $phrase, $status );
$phrase_queries[ $phrase ] = $queries;
}
return $phrase_queries;
}

View File

@@ -1,146 +0,0 @@
<?php
/**
* /lib/privacy.php
*
* Privacy policy features.
*
* @since 4.0.10
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'admin_init', 'relevanssi_register_privacy_policy' );
add_filter( 'wp_privacy_personal_data_exporters', 'relevanssi_register_exporter', 10 );
add_filter( 'wp_privacy_personal_data_erasers', 'relevanssi_register_eraser', 10 );
/**
* Registers the Relevanssi privacy policy information.
*
* @since 4.0.10
*/
function relevanssi_register_privacy_policy() {
if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
return;
}
$name = 'Relevanssi';
if ( RELEVANSSI_PREMIUM ) {
$name .= ' Premium';
}
$content = '';
if ( 'on' === get_option( 'relevanssi_log_queries' ) ) {
$content = '<h2>' . __( 'What personal data we collect and why we collect it' ) . '</h2>';
if ( 'on' === get_option( 'relevanssi_log_queries_with_ip' ) ) {
$content .= '<h3>' . __( 'IP address for searches', 'relevanssi' ) . '</h3>';
$content .= '<p>' . __( 'All searches performed using the internal site search are logged in the database, including the following information: the search query, the number of hits found, user ID for users who are logged in, date and time and the IP address. The IP address is stored for security and auditing purposes.', 'relevanssi' ) . '</p>';
} else {
$content .= '<p>' . __( 'All searches performed using the internal site search are logged in the database, including the following information: the search query, the number of hits found, user ID for users who are logged in and date and time.', 'relevanssi' ) . '</p>';
}
$interval = intval( get_option( 'relevanssi_trim_logs' ) );
$content .= '<h2>' . __( 'How long we retain your data' ) . '</h2>';
if ( $interval > 0 ) {
// Translators: %d is the number of days.
$content .= '<p>' . sprintf( __( 'The search logs are stored for %d days before they are automatically removed.', 'relevanssi' ), $interval ) . '</p>';
} else {
$content .= '<p>' . __( 'The search logs are stored indefinitely.', 'relevanssi' ) . '</p>';
}
}
wp_add_privacy_policy_content( $name, $content );
}
/**
* Registers the Relevanssi data exporter.
*
* @since 4.0.10
*
* @param array $exporters The exporters array.
*
* @return array The exporters array, with Relevanssi added.
*/
function relevanssi_register_exporter( $exporters ) {
$exporters['relevanssi'] = array(
'exporter_friendly_name' => __( 'Relevanssi Search Logs' ),
'callback' => 'relevanssi_privacy_exporter',
);
return $exporters;
}
/**
* Registers the Relevanssi data eraser.
*
* @since 4.0.10
*
* @param array $erasers The erasers array.
*
* @return array The erasers array, with Relevanssi added.
*/
function relevanssi_register_eraser( $erasers ) {
$erasers['relevanssi'] = array(
'eraser_friendly_name' => __( 'Relevanssi Search Logs' ),
'callback' => 'relevanssi_privacy_eraser',
);
return $erasers;
}
/**
* Exports the log entries based on user email.
*
* @since 4.0.10
*
* @param string $email_address The user email address.
* @param int $page The page number, default 1.
*
* @return array Two-item array: 'done' is a Boolean that tells if the exporter is
* done, 'data' contains the actual data.
*/
function relevanssi_privacy_exporter( $email_address, $page = 1 ) {
$user = get_user_by( 'email', $email_address );
if ( ! $user ) {
// No user found.
return array(
'done' => true,
'data' => array(),
);
} else {
$result = relevanssi_export_log_data( $user->ID, $page );
return array(
'done' => $result['done'],
'data' => $result['data'],
);
}
}
/**
* Erases the log entries based on user email.
*
* @since 4.0.10
*
* @param string $email_address The user email address.
* @param int $page The page number, default 1.
*
* @return array Four-item array: 'items_removed' is a Boolean that tells if
* something was removed, 'done' is a Boolean that tells if the eraser is done,
* 'items_retained' is always false, 'messages' is always an empty array.
*/
function relevanssi_privacy_eraser( $email_address, $page = 1 ) {
$user = get_user_by( 'email', $email_address );
if ( ! $user ) {
// No user found.
return array(
'items_removed' => false,
'done' => true,
'items_retained' => false,
'messages' => array(),
);
} else {
$result = relevanssi_erase_log_data( $user->ID, $page );
return array(
'items_removed' => $result['items_removed'],
'done' => $result['done'],
'items_retained' => false,
'messages' => array(),
);
}
}

View File

@@ -1,644 +0,0 @@
<?php
/**
* /lib/search-query-restrictions.php
*
* Responsible for converting query parameters to MySQL query restrictions.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Processes the arguments to create the query restrictions.
*
* All individual parts are tested.
*
* @param array $args The query arguments.
*
* @return array An array containing `query_restriction` and `query_join`.
*/
function relevanssi_process_query_args( $args ) {
$query_restrictions = '';
$query_join = '';
$query = '';
$query_no_synonyms = '';
$phrase_query_restrictions = array(
'and' => '',
'or' => array(),
);
if ( function_exists( 'wp_encode_emoji' ) ) {
$query = wp_encode_emoji( $args['q'] );
$query_no_synonyms = wp_encode_emoji( $args['q_no_synonyms'] );
}
if ( $args['sentence'] ) {
$query = relevanssi_remove_quotes( $query );
$query = '"' . $query . '"';
}
if ( is_array( $args['tax_query'] ) ) {
$query_restrictions .= relevanssi_process_tax_query( $args['tax_query_relation'], $args['tax_query'] );
}
if ( is_array( $args['post_query'] ) ) {
$query_restrictions .= relevanssi_process_post_query( $args['post_query'] );
}
if ( is_array( $args['parent_query'] ) ) {
$query_restrictions .= relevanssi_process_parent_query( $args['parent_query'] );
}
if ( is_array( $args['meta_query'] ) ) {
$processed_meta = relevanssi_process_meta_query( $args['meta_query'] );
$query_restrictions .= $processed_meta['where'];
$query_join .= $processed_meta['join'];
}
if ( $args['date_query'] instanceof WP_Date_Query ) {
$query_restrictions .= relevanssi_process_date_query( $args['date_query'] );
}
if ( $args['expost'] ) {
$query_restrictions .= relevanssi_process_expost( $args['expost'] );
}
if ( $args['author'] ) {
$query_restrictions .= relevanssi_process_author( $args['author'] );
}
if ( $args['by_date'] ) {
$query_restrictions .= relevanssi_process_by_date( $args['by_date'] );
}
$phrases = relevanssi_recognize_phrases( $query, $args['operator'] );
if ( $phrases ) {
$phrase_query_restrictions = $phrases;
}
$query_restrictions .= relevanssi_process_post_type(
$args['post_type'],
$args['admin_search'],
$args['include_attachments']
);
if ( $args['post_status'] ) {
$query_restrictions .= relevanssi_process_post_status( $args['post_status'] );
}
return array(
'query_restrictions' => $query_restrictions,
'query_join' => $query_join,
'query_query' => $query,
'query_no_synonyms' => $query_no_synonyms,
'phrase_queries' => $phrase_query_restrictions,
);
}
/**
* Processes the 'in' and 'not in' parameters to MySQL query restrictions.
*
* Checks that the parameters are integers and formulates a MySQL query
* restriction from them. If the same posts are both included and excluded,
* exclusion will take precedence.
*
* Tested.
*
* @param array $post_query An array where included posts are in
* $post_query['in'] and excluded posts are in $post_query['not in'].
*
* @return string MySQL query restrictions matching the array.
*/
function relevanssi_process_post_query( $post_query ) {
$query_restrictions = '';
$valid_exclude_values = array();
if ( ! empty( $post_query['not in'] ) ) {
foreach ( $post_query['not in'] as $post_not_in_id ) {
if ( is_numeric( $post_not_in_id ) ) {
$valid_exclude_values[] = $post_not_in_id;
}
}
$posts = implode( ',', $valid_exclude_values );
if ( ! empty( $posts ) ) {
$query_restrictions .= " AND relevanssi.doc NOT IN ($posts)";
// Clean: $posts is checked to be integers.
}
}
if ( ! empty( $post_query['in'] ) ) {
$valid_values = array();
foreach ( $post_query['in'] as $post_in_id ) {
if ( is_numeric( $post_in_id ) ) {
$valid_values[] = $post_in_id;
}
}
// If same values appear in both arrays, exclusion will override inclusion.
$valid_values = array_diff( $valid_values, $valid_exclude_values );
$posts = implode( ',', $valid_values );
if ( ! empty( $posts ) ) {
$query_restrictions .= " AND relevanssi.doc IN ($posts)";
// Clean: $posts is checked to be integers.
}
}
/**
* Filters the MySQL query for restricting the search by post parameters.
*
* @param string $query_restrictions The MySQL query.
* @param array $post_query The post query parameters.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_post_query_filter', $query_restrictions, $post_query );
}
/**
* Processes the 'parent in' and 'parent not in' parameters to MySQL query
* restrictions.
*
* Checks that the parameters are integers and formulates a MySQL query restriction
* from them. If the same posts are both included and excluded, exclusion will take
* precedence.
*
* Tested.
*
* @param array $parent_query An array where included posts are in
* $post_query['parent in'] and excluded posts are in $post_query['parent not in'].
*
* @return string MySQL query restrictions matching the array.
*/
function relevanssi_process_parent_query( $parent_query ) {
global $wpdb;
$query_restrictions = '';
$valid_exclude_values = array();
if ( isset( $parent_query['parent not in'] ) ) {
foreach ( $parent_query['parent not in'] as $post_not_in_id ) {
if ( is_int( $post_not_in_id ) ) {
$valid_exclude_values[] = $post_not_in_id;
}
}
$posts = implode( ',', $valid_exclude_values );
if ( isset( $posts ) ) {
$query_restrictions .= " AND relevanssi.doc NOT IN (SELECT ID FROM $wpdb->posts WHERE post_parent IN ($posts))";
// Clean: $posts is checked to be integers.
}
}
if ( isset( $parent_query['parent in'] ) ) {
$valid_values = array();
foreach ( $parent_query['parent in'] as $post_in_id ) {
if ( is_int( $post_in_id ) ) {
$valid_values[] = $post_in_id;
}
}
$valid_values = array_diff( $valid_values, $valid_exclude_values );
$posts = implode( ',', $valid_values );
if ( strlen( $posts ) > 0 ) {
$query_restrictions .= " AND relevanssi.doc IN (SELECT ID FROM $wpdb->posts WHERE post_parent IN ($posts))";
// Clean: $posts is checked to be integers.
}
}
/**
* Filters the MySQL query for restricting the search by the post parent.
*
* @param string $query_restrictions The MySQL query.
* @param array $parent_query The parent query parameters.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_parent_query_filter', $query_restrictions, $parent_query );
}
/**
* Processes the meta query parameter to MySQL query restrictions.
*
* Uses the WP_Meta_Query object to parse the query variables to create the MySQL
* JOIN and WHERE clauses.
*
* Tested.
*
* @see WP_Meta_Query
*
* @param array $meta_query A meta query array.
*
* @return array Index 'where' is the WHERE, index 'join' is the JOIN.
*/
function relevanssi_process_meta_query( $meta_query ) {
$mq_vars = array( 'meta_query' => $meta_query );
$mq = new WP_Meta_Query();
$mq->parse_query_vars( $mq_vars );
$meta_sql = $mq->get_sql( 'post', 'relevanssi', 'doc' );
$meta_join = '';
$meta_where = '';
if ( $meta_sql ) {
$meta_join = $meta_sql['join'];
$meta_where = $meta_sql['where'];
}
return array(
'where' => $meta_where,
'join' => $meta_join,
);
}
/**
* Processes the date query parameter to MySQL query restrictions.
*
* Uses the WP_Date_Query object to parse the query variables to create the
* MySQL WHERE clause. By default using a date query will block taxonomy terms
* and user profiles from the search (because they don't have a post ID and
* also don't have date information associated with them). If you want to keep
* the user profiles and taxonomy terms in the search, set the filter hook
* `relevanssi_date_query_non_posts` to return true.
*
* @see WP_Date_Query
*
* @global object $wpdb The WP database interface.
*
* @param WP_Date_Query $date_query A date query object.
*
* @return string The MySQL query restriction.
*/
function relevanssi_process_date_query( $date_query ) {
global $wpdb;
$query_restrictions = '';
if ( method_exists( $date_query, 'get_sql' ) ) {
$sql = $date_query->get_sql(); // Format: AND (the query).
$query = " relevanssi.doc IN (
SELECT DISTINCT(ID) FROM $wpdb->posts WHERE 1 $sql )
";
/**
* If true, include non-posts (users, terms) in searches with a date
* query filter.
*
* @param boolean Allow non-posts? Default false.
*/
if ( apply_filters( 'relevanssi_date_query_non_posts', false ) ) {
$query_restrictions = " AND ( $query OR relevanssi.doc = -1 ) ";
// Clean: $sql generated by $date_query->get_sql() query.
} else {
$query_restrictions = " AND $query ";
// Clean: $sql generated by $date_query->get_sql() query.
}
}
/**
* Filters the MySQL query for restricting the search by the date_query.
*
* @param string $query_restrictions The MySQL query.
* @param WP_Date_Query $date_query The date_query object.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_date_query_filter', $query_restrictions, $date_query );
}
/**
* Processes the post exclusion parameter to MySQL query restrictions.
*
* Takes a comma-separated list of post ID numbers and creates a MySQL query
* restriction from them.
*
* @param string $expost The post IDs to exclude, comma-separated.
*
* @return string The MySQL query restriction.
*/
function relevanssi_process_expost( $expost ) {
$posts_to_exclude = '';
$excluded_post_ids_unchecked = explode( ',', trim( $expost, ' ,' ) );
$excluded_post_ids = array();
foreach ( $excluded_post_ids_unchecked as $excluded_post_id ) {
$excluded_post_ids[] = intval( trim( $excluded_post_id, ' -' ) );
}
$excluded_post_ids_string = implode( ',', $excluded_post_ids );
$posts_to_exclude .= " AND relevanssi.doc NOT IN ($excluded_post_ids_string)";
// Clean: escaped.
return $posts_to_exclude;
}
/**
* Processes the author parameter to MySQL query restrictions.
*
* Takes an array of author ID numbers and creates the MySQL query restriction code
* from them. Negative values are counted as exclusion and positive values as
* inclusion.
*
* Tested.
*
* @global object $wpdb The WP database interface.
*
* @param array $author An array of authors. Positive values are inclusion,
* negative values are exclusion.
*
* @return string The MySQL query restriction.
*/
function relevanssi_process_author( $author ) {
global $wpdb;
$query_restrictions = '';
$author_in = array();
$author_not_in = array();
foreach ( $author as $id ) {
if ( ! is_numeric( $id ) ) {
continue;
}
if ( $id > 0 ) {
$author_in[] = $id;
} else {
$author_not_in[] = abs( $id );
}
}
if ( count( $author_in ) > 0 ) {
$authors = implode( ',', $author_in );
$query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_author IN ($authors))";
// Clean: $authors is always just numbers.
}
if ( count( $author_not_in ) > 0 ) {
$authors = implode( ',', $author_not_in );
$query_restrictions .= " AND relevanssi.doc NOT IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_author IN ($authors))";
// Clean: $authors is always just numbers.
}
/**
* Filters the MySQL query for restricting the search by the post author.
*
* @param string $query_restrictions The MySQL query.
* @param array $author An array of author IDs.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_author_query_filter', $query_restrictions, $author );
}
/**
* Processes the by_date parameter to MySQL query restrictions.
*
* The by_date parameter is a simple data parameter in the format '24h', that is a
* number followed by an unit (h, d, m, y, or w).
*
* Tested.
*
* @global object $wpdb The WP database interface.
*
* @param string $by_date The date parameter.
*
* @return string The MySQL query restriction.
*/
function relevanssi_process_by_date( $by_date ) {
global $wpdb;
$query_restrictions = '';
$u = substr( $by_date, -1, 1 );
switch ( $u ) {
case 'h':
$unit = 'HOUR';
break;
case 'd':
$unit = 'DAY';
break;
case 'm':
$unit = 'MONTH';
break;
case 'y':
$unit = 'YEAR';
break;
case 'w':
$unit = 'WEEK';
break;
default:
$unit = 'DAY';
}
$n = preg_replace( '/[hdmyw]/', '', $by_date );
if ( is_numeric( $n ) ) {
$query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_date > DATE_SUB(NOW(), INTERVAL $n $unit))";
// Clean: $n is always numeric, $unit is Relevanssi-generated.
}
/**
* Filters the MySQL query for restricting the search by the by_date.
*
* @param string $query_restrictions The MySQL query.
* @param string $by_date The by_date parameter.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_by_date_query_filter', $query_restrictions, $by_date );
}
/**
* Extracts the post types from a comma-separated list or an array.
*
* Handles the non-post post types as well (user, taxonomies, etc.) and escapes the
* post types for SQL injections.
*
* Tested.
*
* @param string|array $post_type An array or a comma-separated list of
* post types.
* @param boolean $admin_search True if this is an admin search.
* @param boolean $include_attachments True if attachments are allowed in the
* search.
*
* @global object $wpdb The WP database interface.
*
* @return array Array containing the 'post_type' and 'non_post_post_type' (which
* defaults to null).
*/
function relevanssi_process_post_type( $post_type, $admin_search, $include_attachments ) {
global $wpdb;
// If $post_type is not set, see if there are post types to exclude from the search.
// If $post_type is set, there's no need to exclude, as we only include.
$negative_post_type = null;
if ( ! $post_type && ! $admin_search ) {
$negative_post_type = relevanssi_get_negative_post_type( $include_attachments );
}
$non_post_post_type = null;
$non_post_post_types_array = array();
if ( function_exists( 'relevanssi_get_non_post_post_types' ) ) {
// Relevanssi Premium includes post types which are not actually posts.
$non_post_post_types_array = relevanssi_get_non_post_post_types();
}
if ( $post_type ) {
if ( ! is_array( $post_type ) ) {
$post_types = explode( ',', $post_type );
} else {
$post_types = $post_type;
}
// This array will contain all regular post types involved in the search parameters.
$post_post_types = array_diff( $post_types, $non_post_post_types_array );
// This array has the non-post post types involved.
$non_post_post_types = array_intersect( $post_types, $non_post_post_types_array );
// Escape both for SQL queries, just in case.
$non_post_post_types = esc_sql( $non_post_post_types );
$post_types = esc_sql( $post_post_types );
// Implode to a parameter string, or set to null if empty.
$non_post_post_type = null;
if ( count( $non_post_post_types ) > 0 ) {
$non_post_post_type = "'" . implode( "', '", $non_post_post_types ) . "'";
}
$post_type = null;
if ( count( $post_types ) > 0 ) {
$post_type = "'" . implode( "', '", $post_types ) . "'";
}
}
$query_restrictions = '';
if ( $post_type ) {
$restriction = " AND (
relevanssi.doc IN (
SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_type IN ($post_type)
) *np*
)"; // Clean: $post_type is escaped.
// There are post types involved that are taxonomies or users, so can't
// match to wp_posts. Add a relevanssi.type restriction.
if ( $non_post_post_type ) {
$restriction = str_replace( '*np*', "OR (relevanssi.type IN ($non_post_post_type))", $restriction );
// Clean: $non_post_post_types is escaped.
} else {
// No non-post post types, so remove the placeholder.
$restriction = str_replace( '*np*', '', $restriction );
}
$query_restrictions .= $restriction;
} else {
// No regular post types.
if ( $non_post_post_type ) {
// But there is a non-post post type restriction.
$query_restrictions .= " AND (relevanssi.type IN ($non_post_post_type))";
// Clean: $non_post_post_types is escaped.
}
}
if ( $negative_post_type ) {
$query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_type NOT IN ($negative_post_type))) OR (doc = -1))";
// Clean: $negative_post_type is escaped.
}
/**
* Filters the MySQL query for restricting the search by the post type.
*
* @param string $query_restrictions The MySQL query.
* @param string|array $post_type The post type(s).
* @param boolean $include_attachments True if attachments are allowed.
* @param boolean $admin_search True if this is an admin search.
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_post_type_query_filter', $query_restrictions, $post_type, $include_attachments, $admin_search );
}
/**
* Processes the post status parameter.
*
* Takes the post status parameter and creates a MySQL query restriction from it.
* Checks if this is in admin context: if the query isn't, there's a catch added to
* capture user profiles and taxonomy terms.
*
* @param string $post_status A post status string.
*
* @global WP_Query $wp_query The WP Query object.
* @global object $wpdb The WP database interface.
* @global boolean $relevanssi_admin_test If true, an admin search. for tests.
*
* @return string The MySQL query restriction.
*/
function relevanssi_process_post_status( $post_status ) {
global $wp_query, $wpdb, $relevanssi_admin_test;
$query_restrictions = '';
if ( ! is_array( $post_status ) ) {
$post_statuses = esc_sql( explode( ',', $post_status ) );
} else {
$post_statuses = esc_sql( $post_status );
}
$escaped_post_status = '';
if ( count( $post_statuses ) > 0 ) {
$escaped_post_status = "'" . implode( "', '", $post_statuses ) . "'";
}
if ( $escaped_post_status ) {
$block_non_post_results = false;
if ( $wp_query->is_admin || $relevanssi_admin_test ) {
$block_non_post_results = true;
}
if ( $wp_query->is_admin && isset( $wp_query->query_vars['action'] ) && 'relevanssi_live_search' === $wp_query->query_vars['action'] ) {
$block_non_post_results = false;
}
if ( $block_non_post_results ) {
$query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_status IN ($escaped_post_status))))";
} else {
// The -1 is there to get user profiles and category pages.
$query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
WHERE posts.post_status IN ($escaped_post_status))) OR (doc = -1))";
}
}
/**
* Filters the MySQL query for restricting the search by the post status.
*
* @param string $query_restrictions The MySQL query.
* @param string $post_status The post status(es).
*
* @return string The MySQL query.
*/
return apply_filters( 'relevanssi_post_status_query_filter', $query_restrictions, $post_status );
}
/**
* Adds phrase restrictions to the query.
*
* For OR searches, adds the phrases only for matching terms that are in the
* phrases, achieving the OR search effect for phrases: posts without the phrase
* but with another search term are not excluded from the search. In AND
* searches, all search terms must match to documents containing the phrase.
*
* @param string $query_restrictions The MySQL query restriction for the search.
* @param array $phrase_queries The phrase queries - 'and' contains the
* main query, while 'or' has the phrase-specific queries.
* @param string $term The current search term.
* @param string $operator AND or OR.
*
* @return string The query restrictions with the phrase restrictions added.
*/
function relevanssi_add_phrase_restrictions( $query_restrictions, $phrase_queries, $term, $operator ) {
if ( 'OR' === $operator ) {
$or_queries = array_filter(
$phrase_queries['or'],
function ( $terms ) use ( $term ) {
return relevanssi_stripos( $terms, $term ) !== false;
},
ARRAY_FILTER_USE_KEY
);
if ( $or_queries ) {
$query_restrictions .= ' AND ( '
. implode( ' OR ', array_values( $or_queries ) )
. ' ) ';
}
} else {
$query_restrictions .= $phrase_queries['and'];
}
return $query_restrictions;
}

View File

@@ -1,408 +0,0 @@
<?php
/**
* /lib/search-tax-query.php
*
* Responsible for converting tax_query parameters to MySQL query restrictions.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Processes the tax query to formulate a query restriction to the MySQL query.
*
* @uses relevanssi_process_tax_query_row()
*
* @param string $tax_query_relation The base tax query relation. Default 'and'.
* @param array $tax_query The tax query array.
*
* @return string The query restrictions for the MySQL query.
*/
function relevanssi_process_tax_query( string $tax_query_relation, array $tax_query ) : string {
$query_restrictions = '';
if ( empty( $tax_query_relation ) ) {
$tax_query_relation = 'and';
}
$tax_query_relation = relevanssi_strtolower( $tax_query_relation );
$term_tax_ids = array();
$not_term_tax_ids = array();
$and_term_tax_ids = array();
$exist_queries = array();
$is_sub_row = false;
foreach ( $tax_query as $row ) {
if ( isset( $row['terms'] ) || ( isset( $row['operator'] ) && ( 'not exists' === strtolower( $row['operator'] ) || 'exists' === strtolower( $row['operator'] ) ) ) ) {
list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) =
relevanssi_process_tax_query_row( $row, $is_sub_row, $tax_query_relation, $query_restrictions, $tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries );
} else {
$row_tax_query_relation = $tax_query_relation;
if ( isset( $row['relation'] ) ) {
$row_tax_query_relation = relevanssi_strtolower( $row['relation'] );
}
if ( is_array( $row ) ) {
foreach ( $row as $subrow ) {
$is_sub_row = true;
if ( isset( $subrow['terms'] ) ) {
list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) =
relevanssi_process_tax_query_row( $subrow, $is_sub_row, $tax_query_relation, $query_restrictions, $row_tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries );
}
}
if ( 'or' === $row_tax_query_relation ) {
$query_restrictions .= relevanssi_process_term_tax_ids(
$term_tax_ids,
$not_term_tax_ids,
$and_term_tax_ids,
$exist_queries
);
}
}
}
}
if ( 'or' === $tax_query_relation ) {
$query_restrictions .= relevanssi_process_term_tax_ids(
$term_tax_ids,
$not_term_tax_ids,
$and_term_tax_ids,
$exist_queries
);
}
return $query_restrictions;
}
/**
* Processes one tax_query row.
*
* @global object $wpdb The WordPress database interface.
*
* @param array $row The tax_query row array.
* @param boolean $is_sub_row True if this is a subrow.
* @param string $global_relation The global tax_query relation (AND or OR).
* @param string $query_restrictions The MySQL query restriction.
* @param string $tax_query_relation The tax_query relation.
* @param array $term_tax_ids Array of term taxonomy IDs.
* @param array $not_term_tax_ids Array of excluded term taxonomy IDs.
* @param array $and_term_tax_ids Array of AND term taxonomy IDs.
* @param array $exist_queries MySQL queries for EXIST subqueries.
*
* @return array Returns an array where the first item is the updated
* $query_restrictions, then $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids
* and $exist_queries.
*/
function relevanssi_process_tax_query_row( array $row, bool $is_sub_row,
string $global_relation, string $query_restrictions, string $tax_query_relation,
array $term_tax_ids, array $not_term_tax_ids, array $and_term_tax_ids,
array $exist_queries ) : array {
global $wpdb;
$local_term_tax_ids = array();
$local_not_term_tax_ids = array();
$local_and_term_tax_ids = array();
$term_tax_id = array();
$exists_query = false;
if ( isset( $row['operator'] ) && ( 'exists' === strtolower( $row['operator'] ) || 'not exists' === strtolower( $row['operator'] ) ) ) {
$exists_query = true;
}
if ( $exists_query ) {
$row['field'] = 'exists';
}
if ( ! isset( $row['field'] ) ) {
$row['field'] = 'term_id'; // In case 'field' is not set, go with the WP default of 'term_id'.
}
$row['field'] = strtolower( $row['field'] ); // In some cases, you can get 'ID' instead of 'id'.
if ( in_array( $row['field'], array( 'slug', 'name', 'id', 'term_id' ), true ) ) {
$term_tax_id = relevanssi_term_tax_id_from_row( $row );
}
if ( 'term_taxonomy_id' === $row['field'] ) {
if ( ! is_array( $row['terms'] ) ) {
$row['terms'] = array( $row['terms'] );
}
$term_tax_id = array_filter( $row['terms'], 'is_numeric' );
}
if ( ! $exists_query && ( ! isset( $row['include_children'] ) || true === $row['include_children'] ) ) {
foreach ( $term_tax_id as $t_id ) {
$t_term = get_term_by( 'term_taxonomy_id', $t_id, $row['taxonomy'] );
$t_id = $t_term->term_id;
$kids = get_term_children( $t_id, $row['taxonomy'] );
foreach ( $kids as $kid ) {
$kid_term_tax_id = relevanssi_get_term_tax_id( $kid, $row['taxonomy'] );
if ( $kid_term_tax_id ) {
// In some weird cases, this may be null. See: https://wordpress.org/support/topic/childrens-of-chosen-product_cat-not-showing-up/.
$term_tax_id[] = $kid_term_tax_id;
}
}
}
}
$term_tax_id = array_unique( $term_tax_id );
if ( ! empty( $term_tax_id ) ) {
$n = count( $term_tax_id );
$term_tax_id = implode( ',', $term_tax_id );
$tq_operator = 'IN'; // Assuming the default operator "IN", unless something else is provided.
if ( isset( $row['operator'] ) ) {
$tq_operator = strtoupper( $row['operator'] );
}
if ( ! in_array( $tq_operator, array( 'IN', 'NOT IN', 'AND' ), true ) ) {
$tq_operator = 'IN';
}
if ( 'and' === $tax_query_relation ) {
if ( 'AND' === $tq_operator ) {
$query_restrictions .= " AND relevanssi.doc IN (
SELECT ID FROM $wpdb->posts WHERE 1=1
AND (
SELECT COUNT(1)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($term_tax_id)
AND tr.object_id = $wpdb->posts.ID ) = $n
)";
// Clean: $term_tax_id and $n are Relevanssi-generated.
} else {
if ( 'or' === $global_relation ) {
$local_and_term_tax_ids[] = $term_tax_id;
} else {
$query_restrictions .= " AND relevanssi.doc $tq_operator (
SELECT DISTINCT(tr.object_id)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($term_tax_id))";
// Clean: all variables are Relevanssi-generated.
}
}
} else {
if ( 'IN' === $tq_operator ) {
$local_term_tax_ids[] = $term_tax_id;
}
if ( 'NOT IN' === $tq_operator ) {
$local_not_term_tax_ids[] = $term_tax_id;
}
if ( 'AND' === $tq_operator ) {
$local_and_term_tax_ids[] = $term_tax_id;
}
}
} else {
global $wp_query;
$wp_query->is_category = false;
}
$copy_term_tax_ids = false;
if ( ! $is_sub_row ) {
$copy_term_tax_ids = true;
}
if ( $is_sub_row && ( 'or' === $global_relation || 'or' === $tax_query_relation ) ) {
$copy_term_tax_ids = true;
}
if ( $copy_term_tax_ids ) {
$term_tax_ids = array_merge( $term_tax_ids, $local_term_tax_ids );
$not_term_tax_ids = array_merge( $not_term_tax_ids, $local_not_term_tax_ids );
$and_term_tax_ids = array_merge( $and_term_tax_ids, $local_and_term_tax_ids );
}
if ( $exists_query ) {
$taxonomy = $row['taxonomy'];
$operator = 'IN';
if ( 'not exists' === strtolower( $row['operator'] ) ) {
$operator = 'NOT IN';
}
$exist_query_sql = " relevanssi.doc $operator (
SELECT DISTINCT(tr.object_id)
FROM $wpdb->term_relationships AS tr, $wpdb->term_taxonomy AS tt
WHERE tr.term_taxonomy_id = tt.term_taxonomy_id
AND tt.taxonomy = '$taxonomy' )";
$exist_queries[] = $exist_query_sql;
if ( 'and' === $tax_query_relation ) {
$query_restrictions .= ' AND ' . $exist_query_sql;
}
}
return array(
$query_restrictions,
$term_tax_ids,
$not_term_tax_ids,
$and_term_tax_ids,
$exist_queries,
);
}
/**
* Generates query restrictions from the term taxonomy ids.
*
* Combines different term tax ID arrays into a set of query restrictions that
* can be used in an OR query.
*
* @global object $wpdb The WP database interface.
*
* @param array $term_tax_ids The regular terms.
* @param array $not_term_tax_ids The NOT terms.
* @param array $and_term_tax_ids The AND terms.
* @param array $exist_queries The EXIST queries.
*
* @return string The MySQL query restrictions.
*/
function relevanssi_process_term_tax_ids( array $term_tax_ids, array $not_term_tax_ids,
array $and_term_tax_ids, array $exist_queries ) : string {
global $wpdb;
$query_restriction_parts = array();
$query_restrictions = '';
$term_tax_ids = array_unique( $term_tax_ids );
if ( count( $term_tax_ids ) > 0 ) {
$term_tax_ids = implode( ',', $term_tax_ids );
$query_restriction_parts[] = " relevanssi.doc IN (
SELECT DISTINCT(tr.object_id)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($term_tax_ids)
)";
// Clean: all variables are Relevanssi-generated.
}
if ( count( $not_term_tax_ids ) > 0 ) {
$not_term_tax_ids = implode( ',', $not_term_tax_ids );
$query_restriction_parts[] .= " relevanssi.doc NOT IN (
SELECT DISTINCT(tr.object_id)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($not_term_tax_ids)
)";
// Clean: all variables are Relevanssi-generated.
}
if ( count( $and_term_tax_ids ) > 0 ) {
$single_term_ids = array();
foreach ( $and_term_tax_ids as $term_ids ) {
$n = count( explode( ',', $term_ids ) );
if ( 1 === $n ) {
$single_term_ids[] = $term_ids;
continue;
}
$query_restriction_parts[] .= " relevanssi.doc IN (
SELECT ID FROM $wpdb->posts WHERE 1=1
AND (
SELECT COUNT(1)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($term_ids)
AND tr.object_id = $wpdb->posts.ID ) = $n
)";
// Clean: all variables are Relevanssi-generated.
}
if ( count( $single_term_ids ) > 0 ) {
$n = count( $single_term_ids );
$term_ids = implode( ',', $single_term_ids );
$query_restriction_parts[] .= " relevanssi.doc IN (
SELECT ID FROM $wpdb->posts WHERE 1=1
AND (
SELECT COUNT(1)
FROM $wpdb->term_relationships AS tr
WHERE tr.term_taxonomy_id IN ($term_ids)
AND tr.object_id = $wpdb->posts.ID ) = $n
)";
// Clean: all variables are Relevanssi-generated.
}
}
if ( $exist_queries ) {
$query_restriction_parts = array_merge( $query_restriction_parts, $exist_queries );
}
if ( count( $query_restriction_parts ) > 1 ) {
$query_restrictions .= '(';
}
$query_restrictions .= implode( ' OR', $query_restriction_parts );
if ( count( $query_restriction_parts ) > 1 ) {
$query_restrictions .= ')';
}
if ( $query_restrictions ) {
$query_restrictions = ' AND ' . $query_restrictions;
}
return $query_restrictions;
}
/**
* Gets and sanitizes the taxonomy name and slug parameters.
*
* Checks parameters: if they're numeric, pass them for term_id filtering,
* otherwise sanitize and create a comma-separated list.
*
* @param string|array $terms_parameter The 'terms' field from the tax_query
* row.
* @param string $taxonomy The taxonomy name.
* @param string $field_name The field name ('slug', 'name').
*
* @return array An array containing numeric terms and the list of sanitized
* term names.
*/
function relevanssi_get_term_in( $terms_parameter, string $taxonomy,
string $field_name ) : array {
$numeric_terms = array();
$names = array();
if ( ! is_array( $terms_parameter ) ) {
$terms_parameter = array( $terms_parameter );
}
foreach ( $terms_parameter as $name ) {
$term = get_term_by( $field_name, $name, $taxonomy );
if ( ! $term ) {
if ( ctype_digit( strval( $name ) ) ) {
$numeric_terms[] = $name;
}
} else {
if ( isset( $term->term_id ) && in_array( $field_name, array( 'slug', 'name' ), true ) ) {
$names[] = "'" . esc_sql( $name ) . "'";
} else {
$numeric_terms[] = $name;
}
}
}
return array(
'numeric_terms' => implode( ',', $numeric_terms ),
'term_in' => implode( ',', $names ),
);
}
/**
* Gets the term_tax_id from a row with 'field' set to 'slug' or 'name'.
*
* If the slugs or names are all numeric values, will switch the 'field'
* parameter to 'term_id'.
*
* @param array $row The taxonomy query row.
*
* @return array An array of term taxonomy IDs.
*/
function relevanssi_term_tax_id_from_row( array $row ) : array {
global $wpdb;
$type = $row['field'];
$term_in_results = relevanssi_get_term_in( $row['terms'], $row['taxonomy'], $type );
$numeric_terms = $term_in_results['numeric_terms'];
$term_in = $term_in_results['term_in'];
$term_tax_id = array();
if ( ! empty( $numeric_terms ) ) {
$type = 'term_id';
$term_in = $numeric_terms;
}
if ( ! empty( $term_in ) ) {
$row_taxonomy = sanitize_text_field( $row['taxonomy'] );
$tt_q = "SELECT tt.term_taxonomy_id
FROM $wpdb->term_taxonomy AS tt
LEFT JOIN $wpdb->terms AS t ON (tt.term_id=t.term_id)
WHERE tt.taxonomy = '$row_taxonomy' AND t.$type IN ($term_in)";
// Clean: $row_taxonomy is sanitized, each term in $term_in is sanitized.
$term_tax_id = $wpdb->get_col( $tt_q ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
}
return $term_tax_id;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,207 +0,0 @@
<?php
/**
* /lib/shortcodes.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_shortcode( 'search', 'relevanssi_shortcode' );
add_shortcode( 'noindex', 'relevanssi_noindex_shortcode' );
add_shortcode( 'searchform', 'relevanssi_search_form' );
/**
* Creates a link to search results.
*
* Using this is generally not a brilliant idea, actually. Google doesn't like
* it if you create links to internal search results.
*
* Usage: [search term='tomato']tomatoes[/search] would create a link like this:
* <a href="/?s=tomato">tomatoes</a>
*
* Set 'phrase' to something else than 'not' to make the search term a phrase.
*
* @global object $wpdb The WordPress database interface.
*
* @param array $atts The shortcode attributes. If 'term' is set, will use
* it as the search term, otherwise the content word is used as the term.
* @param string $content The content inside the shortcode tags.
*
* @return string A link to search results.
*/
function relevanssi_shortcode( $atts, $content ) {
$attributes = shortcode_atts(
array(
'term' => false,
'phrase' => 'not',
),
$atts
);
$term = $attributes['term'];
$phrase = $attributes['phrase'];
if ( false !== $term ) {
$term = rawurlencode( relevanssi_strtolower( $term ) );
} else {
$term = rawurlencode( wp_strip_all_tags( relevanssi_strtolower( $content ) ) );
}
if ( 'not' !== $phrase ) {
$term = '%22' . $term . '%22';
}
$link = get_bloginfo( 'url' ) . "/?s=$term";
$pre = "<a rel='nofollow' href='$link'>"; // rel='nofollow' for Google.
$post = '</a>';
return $pre . do_shortcode( $content ) . $post;
}
/**
* Does nothing.
*
* In normal use, the [noindex] shortcode does nothing.
*
* @param array $atts The shortcode attributes. Not used.
* @param string $content The content inside the shortcode tags.
*
* @return string The shortcode content.
*/
function relevanssi_noindex_shortcode( $atts, $content ) {
return do_shortcode( $content );
}
/**
* Returns nothing.
*
* During indexing, the [noindex] shortcode returns nothing.
*
* @param array $atts The shortcode attributes. Not used.
* @param string $content The content inside the shortcode tags.
*
* @return string An empty string.
*/
function relevanssi_noindex_shortcode_indexing( $atts, $content ) {
return '';
}
/**
* Returns a search form.
*
* Returns a search form generated by get_search_form(). Any attributes passed to the
* shortcode will be passed onto the search form, for example like this:
*
* [searchform post_types='post,product']
*
* This would add a
*
* <input type="hidden" name="post_types" value="post,product" />
*
* to the search form.
*
* @param array $atts The shortcode attributes.
*
* @return string A search form.
*/
function relevanssi_search_form( $atts ) {
$form = get_search_form( false );
if ( is_array( $atts ) ) {
$additional_fields = array();
foreach ( $atts as $key => $value ) {
if ( 'dropdown' === substr( $key, 0, 8 ) ) {
$key = 'dropdown';
}
if ( 'checklist' === substr( $key, 0, 9 ) ) {
$key = 'checklist';
}
if ( 'post_type_boxes' === $key ) {
$post_types = explode( ',', $value );
if ( is_array( $post_types ) ) {
$post_type_objects = get_post_types( array(), 'objects' );
$additional_fields[] = '<div class="post_types"><strong>Post types</strong>: ';
foreach ( $post_types as $post_type ) {
$checked = '';
if ( '*' === substr( $post_type, 0, 1 ) ) {
$post_type = substr( $post_type, 1 );
$checked = ' checked="checked" ';
}
if ( isset( $post_type_objects[ $post_type ] ) ) {
$additional_fields[] = '<span class="post_type post_type_' . $post_type . '">'
. '<input type="checkbox" name="post_types[]" value="' . $post_type . '"' . $checked . '/> '
. $post_type_objects[ $post_type ]->name . '</span>';
}
}
$additional_fields[] = '</div>';
}
} elseif ( 'dropdown' === $key && 'post_type' === $value ) {
$field = '<select name="post_type">';
$types = get_option( 'relevanssi_index_post_types' );
if ( ! is_array( $types ) ) {
$types = array();
}
foreach ( $types as $type ) {
if ( post_type_exists( $type ) ) {
$object = get_post_type_object( $type );
$field .= '<option value="' . $type . '">' . $object->labels->singular_name . '</option>';
}
}
$field .= '</select>';
$additional_fields[] = $field;
} elseif ( 'dropdown' === $key && 'post_type' !== $value ) {
$name = $value;
if ( 'category' === $value ) {
$name = 'cat';
}
if ( 'post_tag' === $value ) {
$name = 'tag';
}
$args = array(
'taxonomy' => $value,
'echo' => 0,
'hide_if_empty' => true,
'show_option_none' => __( 'None' ),
'name' => $name,
);
$additional_fields[] = wp_dropdown_categories( $args );
} elseif ( 'checklist' === $key && 'post_type' !== $value ) {
$name = $value;
if ( 'category' === $value ) {
$name = 'cat';
}
if ( 'post_tag' === $value ) {
$name = 'tag';
}
$args = array(
'taxonomy' => $value,
'echo' => 0,
);
if ( ! function_exists( 'wp_terms_checklist' ) ) {
include ABSPATH . 'wp-admin/includes/template.php';
}
$checklist = wp_terms_checklist( 0, $args );
$checklist = str_replace( 'post_category', 'cats', $checklist );
$checklist = str_replace( 'tax_input[post_tag]', 'tags', $checklist );
$checklist = str_replace( "disabled='disabled'", '', $checklist );
$checklist = preg_replace( '/tax_input\[(.*?)\]/', '\1', $checklist );
$additional_fields[] = $checklist;
} else {
$key = esc_attr( $key );
$value = esc_attr( $value );
$additional_fields[] = "<input type='hidden' name='$key' value='$value' />";
}
}
$form = str_replace( '</form>', implode( "\n", $additional_fields ) . '</form>', $form );
}
/**
* Filters the Relevanssi shortcode search form before it's used.
*
* @param string $form The form HTML code.
* @param array $atts The shortcode attributes.
*/
return apply_filters( 'relevanssi_search_form', $form, $atts );
}

View File

@@ -1,451 +0,0 @@
<?php
/**
* /lib/sorting.php
*
* Sorting functions.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Gets the next key-direction pair from the orderby array.
*
* Fetches a key-direction pair from the orderby array. Converts key names to
* match the post object parameters when necessary and seeds the random
* generator, if required.
*
* @param array $orderby An array of key-direction pairs.
*
* @return array A set of 'key', 'dir' for direction and 'compare' for proper
* comparison method.
*/
function relevanssi_get_next_key( &$orderby ) {
if ( ! is_array( $orderby ) || count( $orderby ) < 1 ) {
// Nothing to see here.
return array(
'key' => null,
'dir' => null,
'compare' => null,
);
}
list( $key ) = array_keys( $orderby );
$dir = $orderby[ $key ];
unset( $orderby[ $key ] );
$key = strtolower( $key );
if ( 'rand' === strtolower( $dir ) ) {
$key = 'rand';
}
// Correcting the key for couple of shorthand cases.
switch ( $key ) {
case 'title':
$key = 'post_title';
break;
case 'date':
$key = 'post_date';
break;
case 'modified':
$key = 'post_modified';
break;
case 'parent':
$key = 'post_parent';
break;
case 'type':
$key = 'post_type';
break;
case 'name':
$key = 'post_name';
break;
case 'author':
$key = 'post_author';
break;
case 'relevance':
$key = 'relevance_score';
break;
case 'distance':
$key = 'proximity';
break;
}
$numeric_keys = array(
'meta_value_num',
'menu_order',
'ID',
'post_parent',
'post_author',
'comment_count',
'relevance_score',
'proximity',
);
$date_keys = array(
'post_date',
'post_date_gmt',
'post_modified',
'post_modified_gmt',
);
$filter_keys = array( 'post_type' );
$compare = 'string';
if ( in_array( $key, $numeric_keys, true ) ) {
$compare = 'number';
} elseif ( in_array( $key, $filter_keys, true ) ) {
$compare = 'filter';
} elseif ( in_array( $key, $date_keys, true ) ) {
$compare = 'date';
}
/**
* Lets you choose the compare method for fields.
*
* @param string $compare The compare method, can be 'string', 'number' or
* 'date'.
* @param string $key The name of the custom field key.
*
* @return string The compare method.
*/
$compare = apply_filters( 'relevanssi_sort_compare', $compare, $key );
if ( ! in_array( $compare, array( 'string', 'number', 'date', 'filter' ), true ) ) {
// Not a valid value, fall back.
$compare = 'string';
}
if ( 'rand(' === substr( $key, 0, 5 ) ) {
$parts = explode( '(', $key );
$dir = intval( trim( str_replace( ')', '', $parts[1] ) ) );
$key = 'rand';
}
if ( 'rand' === $key ) {
if ( is_numeric( $dir ) ) {
// A specific random seed is requested.
mt_srand( $dir ); // phpcs:ignore WordPress.WP.AlternativeFunctions
}
} else {
$dir = strtolower( $dir );
if ( 'asc' !== $dir ) {
$dir = 'desc';
}
}
$values = array(
'key' => $key,
'dir' => $dir,
'compare' => $compare,
);
return $values;
}
/**
* Gets the values for comparing items for given key.
*
* Fetches the key values for the item pair. If random order is required, this
* function will randomize the order.
*
* @global array $relevanssi_meta_query The meta query used for the sorting.
*
* @param string $key The key used.
* @param object $item_1 The first post object to compare.
* @param object $item_2 The second post object to compare.
*
* @return array Array with the key values: 'key1' and 'key2', respectively.
*/
function relevanssi_get_compare_values( $key, $item_1, $item_2 ) {
if ( 'rand' === $key ) {
do {
$key1 = wp_rand();
$key2 = wp_rand();
} while ( $key1 === $key2 );
$keys = array(
'key1' => $key1,
'key2' => $key2,
);
return $keys;
}
$key1 = '';
$key2 = '';
if ( 'meta_value' === $key || 'meta_value_num' === $key ) {
global $wp_query;
// Get the name of the field from the global WP_Query.
$key = $wp_query->query_vars['meta_key'] ?? null;
if ( empty( $key ) ) {
// If empty, try the Relevanssi meta_query.
global $relevanssi_meta_query;
foreach ( $relevanssi_meta_query as $meta_row ) {
// There may be many rows. Choose the one where there's just key
// and no value.
if ( ! is_array( $meta_row ) ) {
continue;
}
if ( isset( $meta_row['value'] ) ) {
continue;
}
if ( isset( $meta_row['key'] ) ) {
$key = $meta_row['key'];
}
}
if ( empty( $key ) ) {
// The key is not set.
return array( '', '' );
}
}
$key1 = get_post_meta( $item_1->ID, $key, true );
if ( empty( $key1 ) ) {
/**
* Adds in a missing sorting value.
*
* In some cases the sorting method may not have values for all
* posts (for example when sorting by 'menu_order'). If you still
* want to use a sorting method like this, you can use this function
* to fill in a value (in the case of 'menu_order', for example, one
* could use PHP_INT_MAX.)
*
* @param string $key1 The value to filter.
* @param string $key The name of the key.
*/
$key1 = apply_filters( 'relevanssi_missing_sort_key', $key1, $key );
}
$key2 = get_post_meta( $item_2->ID, $key, true );
if ( empty( $key2 ) ) {
/**
* Documented in lib/sorting.php.
*/
$key2 = apply_filters( 'relevanssi_missing_sort_key', $key2, $key );
}
} elseif ( 'proximity' === $key && function_exists( 'relevanssi_get_proximity_values' ) ) {
list( $key1, $key2 ) = relevanssi_get_proximity_values( $item_1, $item_2 );
} else {
global $relevanssi_meta_query;
if ( isset( $item_1->$key ) ) {
$key1 = relevanssi_strtolower( $item_1->$key );
} elseif ( isset( $relevanssi_meta_query[ $key ] ) ) {
// Named meta queries.
$key1 = get_post_meta( $item_1->ID, $relevanssi_meta_query[ $key ]['key'], true );
} else {
/**
* Documented in lib/sorting.php.
*/
$key1 = apply_filters( 'relevanssi_missing_sort_key', $key1, $key );
}
if ( isset( $item_2->$key ) ) {
$key2 = relevanssi_strtolower( $item_2->$key );
} elseif ( isset( $relevanssi_meta_query[ $key ] ) ) {
// Named meta queries.
$key2 = get_post_meta( $item_2->ID, $relevanssi_meta_query[ $key ]['key'], true );
} else {
/**
* Documented in lib/sorting.php.
*/
$key2 = apply_filters( 'relevanssi_missing_sort_key', $key2, $key );
}
}
if ( is_array( $key1 ) ) {
$key1 = relevanssi_flatten_array( $key1 );
}
if ( is_array( $key2 ) ) {
$key2 = relevanssi_flatten_array( $key2 );
}
$key1 = $key1 ?? '';
$key2 = $key2 ?? '';
$keys = array(
'key1' => $key1,
'key2' => $key2,
);
return $keys;
}
/**
* Compares two values.
*
* Compares two sorting keys using date based comparison, string comparison or
* numeric comparison.
*
* @param string $key1 The first key.
* @param string $key2 The second key.
* @param string $compare The comparison method; possible values are 'date' for
* date comparisons and 'string' for string comparison, everything else is
* considered a numeric comparison.
*
* @return int $val Returns < 0 if key1 is less than key2; > 0 if key1 is
* greater than key2, and 0 if they are equal.
*/
function relevanssi_compare_values( $key1, $key2, $compare ) {
$val = 0;
if ( 'date' === $compare ) {
if ( strtotime( $key1 ) > strtotime( $key2 ) ) {
$val = 1;
} elseif ( strtotime( $key1 ) < strtotime( $key2 ) ) {
$val = -1;
}
} elseif ( 'string' === $compare ) {
$val = relevanssi_mb_strcasecmp( $key1, $key2 );
} elseif ( 'filter' === $compare ) {
$val = relevanssi_filter_compare( $key1, $key2 );
} else {
if ( $key1 > $key2 ) {
$val = 1;
} elseif ( $key1 < $key2 ) {
$val = -1;
}
}
return $val;
}
/**
* Compares two values using order array from a filter.
*
* Compares two sorting keys using a sorted array that contains value => order
* pairs. Uses the 'relevanssi_comparison_order' filter to get the sorting
* guidance array.
*
* @param string $key1 The first key.
* @param string $key2 The second key.
*
* @return int $val Returns < 0 if key1 is less than key2; > 0 if key1 is
* greater than key2, and 0 if they are equal.
*/
function relevanssi_filter_compare( $key1, $key2 ) {
/**
* Provides the sorting order for the filter.
*
* The array should contain the possible key values as keys and their order
* in the values, like this:
*
* $order = array(
* 'post' => 0,
* 'page' => 1,
* 'book' => 2,
* );
*
* This would sort posts first, pages second, books third. Values that do
* not appear in the array are sorted last.
*
* @param array Sorting guidance array.
*/
$order = apply_filters( 'relevanssi_comparison_order', array() );
// Set the default values so that if the key is not found in the array, it's
// last.
$max_key = ! empty( $order ) ? max( $order ) : 0;
$val_1 = isset( $order[ $key1 ] ) ? $order[ $key1 ] : $max_key + 1;
$val_2 = isset( $order[ $key2 ] ) ? $order[ $key2 ] : $max_key + 1;
return $val_1 - $val_2;
}
/**
* Compares values using multiple levels of sorting keys.
*
* Comparison function for usort() using multiple levels of sorting methods. If
* one level produces a tie, the sort will get a next level of sorting methods.
*
* @global array $relevanssi_keys An array of sorting keys by level.
* @global array $relevanssi_dirs An array of sorting directions by level.
* @global array $relevanssi_compares An array of comparison methods by level.
*
* @param object $a A post object.
* @param object $b A post object.
*
* @return int $val Returns < 0 if a is less than b; > 0 if a is greater
* than b, and 0 if they are equal.
*/
function relevanssi_cmp_function( $a, $b ) {
global $relevanssi_keys, $relevanssi_dirs, $relevanssi_compares;
$level = -1;
$val = 0;
if ( is_integer( $a ) ) {
$a = get_post( $a );
}
if ( is_integer( $b ) ) {
$b = get_post( $b );
}
while ( 0 === $val ) {
$level++;
if ( ! isset( $relevanssi_keys[ $level ] ) ) {
// No more levels; we've hit the bedrock.
$level--;
break;
}
$compare = $relevanssi_compares[ $level ];
$compare_values = relevanssi_get_compare_values( $relevanssi_keys[ $level ], $a, $b );
$val = relevanssi_compare_values( $compare_values['key1'], $compare_values['key2'], $compare );
}
if ( 'desc' === $relevanssi_dirs[ $level ] ) {
$val = $val * -1;
}
return $val;
}
/**
* Sorts post objects.
*
* Sorts post objects using multiple levels of sorting methods. This function
* was originally written by Matthew Hood and published in the PHP manual
* comments.
*
* The actual sorting is handled by relevanssi_cmp_function().
*
* @see relevanssi_cmp_function()
*
* @global array $relevanssi_keys An array of sorting keys by level.
* @global array $relevanssi_dirs An array of sorting directions by level.
* @global array $relevanssi_compares An array of comparison methods by level.
* @global array $relevanssi_meta_query The meta query array.
*
* @param array $data The posts to sort are in $data[0], used as a
* reference.
* @param array $orderby The array of orderby rules with directions.
* @param array $meta_query The meta query array, in case it's needed for meta
* query based sorting.
*/
function relevanssi_object_sort( &$data, $orderby, $meta_query ) {
global $relevanssi_keys, $relevanssi_dirs, $relevanssi_compares, $relevanssi_meta_query;
$relevanssi_keys = array();
$relevanssi_dirs = array();
$relevanssi_compares = array();
$relevanssi_meta_query = $meta_query; // Store in a global variable to avoid complicated parameter passing.
do {
$values = relevanssi_get_next_key( $orderby );
if ( ! empty( $values['key'] ) ) {
$relevanssi_keys[] = $values['key'];
$relevanssi_dirs[] = $values['dir'];
$relevanssi_compares[] = $values['compare'];
}
} while ( ! empty( $values['key'] ) );
usort( $data, 'relevanssi_cmp_function' );
}
/**
* Sorts strings by length.
*
* A sorting function that sorts strings by length. Uses relevanssi_strlen() to
* count the string length.
*
* @see relevanssi_strlen()
*
* @param string $a String A.
* @param string $b String B.
*
* @return int Negative value, if string A is longer; zero, if strings are
* equally long; positive, if string B is longer.
*/
function relevanssi_strlen_sort( $a, $b ) {
return relevanssi_strlen( $b ) - relevanssi_strlen( $a );
}

View File

@@ -1,420 +0,0 @@
<?php
/**
* /lib/stopwords.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Reads automatically the correct stopwords for the current language set in
* WPLANG.
*
* The stopwords are first read from the wp_relevanssi_stopwords database table
* (which is where they were stored before they were moved to an option), but
* if the table is empty (as it will be in new installations), the stopwords are
* read from the stopword file for the current language (defaulting to en_US).
*
* @global object $wpdb The WordPress database interface.
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param boolean $verbose If true, output results. Default false.
*
* @return string Result: 'database' for reading from database, 'file' for
* reading from file, 'no_file' for non-existing file, 'file_error' for file
* with non-acceptable data.
*/
function relevanssi_populate_stopwords( $verbose = false ) {
global $relevanssi_variables, $wpdb;
$stopword_table = $relevanssi_variables['stopword_table'];
$stopwords_from_table = $wpdb->get_col( "SELECT * FROM $stopword_table" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ( count( $stopwords_from_table ) > 1 ) {
array_walk( $stopwords_from_table, 'relevanssi_add_single_stopword' );
$verbose && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__( 'Added stopwords from the database.', 'relevanssi' )
);
return 'database';
}
$language = relevanssi_get_current_language();
$stopword_file = $relevanssi_variables['plugin_dir']
. 'stopwords/stopwords.' . $language;
if ( ! file_exists( $stopword_file ) ) {
$verbose && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the language code.
esc_html__(
"The stopword file for the language '%s' doesn't exist.",
'relevanssi'
),
esc_html( $language )
)
);
return 'no_file';
}
$stopwords = array();
include $stopword_file; // Contains the stopwords in the $stopwords array.
if ( ! is_array( $stopwords ) ) {
$verbose && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__(
"Couldn't read the stopwords from the file.",
'relevanssi'
)
);
return 'file_error';
}
array_walk( $stopwords, 'relevanssi_add_single_stopword' );
$verbose && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__( 'Added stopwords from the stopword file.', 'relevanssi' )
);
return 'file';
}
/**
* Fetches the list of stopwords in the current language.
*
* Gets the list of stopwords from the relevanssi_stopwords option using the
* current language.
*
* @return array An array of stopwords; if nothing is found, returns an empty
* array.
*/
function relevanssi_fetch_stopwords() {
$current_language = relevanssi_get_current_language();
$stopwords_array = get_option( 'relevanssi_stopwords', array() );
$stopwords = isset( $stopwords_array[ $current_language ] ) ? $stopwords_array[ $current_language ] : '';
$stopword_list = $stopwords ? explode( ',', $stopwords ) : array();
return $stopword_list;
}
/**
* Adds a stopword to the list of stopwords.
*
* @param string $term The stopword that is added.
* @param boolean $verbose If true, print out notices. Default true.
*
* @return boolean True, if success; false otherwise.
*/
function relevanssi_add_stopword( $term, $verbose = true ) {
if ( empty( $term ) ) {
return false;
}
$total_stopwords = 0;
$successfully_added = 0;
$terms = explode( ',', $term );
if ( count( $terms ) > 1 ) {
$total_stopwords = count( $terms );
$successfully_added = array_reduce(
$terms,
function ( $counter, $term ) {
$success = relevanssi_add_single_stopword( trim( $term ) );
$success && $counter++;
return $counter;
},
0
);
$verbose &&
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// translators: %1$d is the successful entries, %2$d is the total entries.
esc_html__(
'Successfully added %1$d/%2$d terms to stopwords!',
'relevanssi'
),
intval( $successfully_added ),
intval( $total_stopwords )
)
);
return boolval( $successfully_added );
}
// Add to stopwords.
$success = relevanssi_add_single_stopword( $term );
$term = esc_html( $term );
$verbose && $success && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__( "Term '%s' added to stopwords!", 'relevanssi' ),
esc_html( stripslashes( $term ) )
)
);
$verbose && ! $success && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__( "Couldn't add term '%s' to stopwords!", 'relevanssi' ),
esc_html( stripslashes( $term ) )
)
);
return $success;
}
/**
* Adds a single stopword to the stopword table.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables.
*
* @param string $term The term to add.
*
* @return boolean True if success, false if not.
*/
function relevanssi_add_single_stopword( $term ) {
if ( empty( $term ) ) {
return false;
}
$stopwords = relevanssi_fetch_stopwords();
$term = stripslashes( relevanssi_strtolower( $term ) );
if ( in_array( $term, $stopwords, true ) ) {
return false;
}
$stopwords[] = $term;
$success = relevanssi_update_stopwords( $stopwords );
if ( ! $success ) {
return false;
}
relevanssi_delete_term_from_all_posts( $term );
return true;
}
/**
* Updates the current language stopwords in the stopwords option.
*
* Fetches the stopwords option, replaces the current language stopwords with
* the parameter array and updates the option.
*
* @param array $stopwords An array of stopwords.
*
* @return boolean The return value from update_option().
*/
function relevanssi_update_stopwords( $stopwords ) {
$current_language = relevanssi_get_current_language();
$stopwords_option = get_option( 'relevanssi_stopwords', array() );
$stopwords_option[ $current_language ] = implode( ',', array_filter( $stopwords ) );
return update_option(
'relevanssi_stopwords',
$stopwords_option
);
}
/**
* Deletes a term from all posts in the database, language considered.
*
* If Polylang or WPML are used, deletes the term only from the posts matching
* the current language.
*
* @param string $term The term to delete.
*/
function relevanssi_delete_term_from_all_posts( $term ) {
global $wpdb, $relevanssi_variables;
if ( function_exists( 'pll_languages_list' ) ) {
$term_id = relevanssi_get_language_term_taxonomy_id(
relevanssi_get_current_language()
);
$wpdb->query(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
"DELETE FROM {$relevanssi_variables['relevanssi_table']}
WHERE term=%s
AND doc IN (
SELECT object_id
FROM $wpdb->term_relationships
WHERE term_taxonomy_id = %d
)",
$term,
$term_id
)
);
return;
}
if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
$language = relevanssi_get_current_language( false );
$wpdb->query(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
"DELETE FROM {$relevanssi_variables['relevanssi_table']}
WHERE term=%s
AND doc IN (
SELECT DISTINCT(element_id)
FROM {$wpdb->prefix}icl_translations
WHERE language_code = %s
)",
$term,
$language
)
);
return;
}
// No language defined, just remove from the index.
$wpdb->query(
$wpdb->prepare(
'DELETE FROM ' . $relevanssi_variables['relevanssi_table'] . // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
' WHERE term=%s',
$term
)
);
}
/**
* Removes all stopwords in specific language.
*
* Empties the relevanssi_stopwords option for particular language.
*
* @param boolean $verbose If true, print out notice. Default true.
* @param string $language The language code of stopwords. If empty, removes
* the stopwords for the current language.
*
* @return boolean True, if able to remove the options.
*/
function relevanssi_remove_all_stopwords( $verbose = true, $language = false ) {
if ( ! $language ) {
$language = relevanssi_get_current_language();
}
$stopwords = get_option( 'relevanssi_stopwords', array() );
unset( $stopwords[ $language ] );
$success = update_option( 'relevanssi_stopwords', $stopwords );
$verbose && $success && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__(
'All stopwords removed! Remember to re-index.',
'relevanssi'
)
);
$verbose && ! $success && printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__(
"There was a problem, and stopwords couldn't be removed.",
'relevanssi'
)
);
return $success;
}
/**
* Removes a single stopword.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables.
*
* @param string $term The stopword to remove.
* @param boolean $verbose If true, print out a notice. Default true.
*
* @return boolean True if success, false if not.
*/
function relevanssi_remove_stopword( $term, $verbose = true ) {
$stopwords = relevanssi_fetch_stopwords();
$term = stripslashes( $term );
$stopwords = array_filter(
$stopwords,
function( $stopword ) use ( $term ) {
return $stopword !== $term;
}
);
$success = relevanssi_update_stopwords( $stopwords );
$verbose && $success &&
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"Term '%s' removed from stopwords! Re-index to get it back to index.",
'relevanssi'
),
esc_html( stripslashes( $term ) )
)
);
$verbose && ! $success &&
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"Couldn't remove term '%s' from stopwords!",
'relevanssi'
),
esc_html( stripslashes( $term ) )
)
);
return $success;
}
/**
* Helper function to remove stopwords from an array.
*
* Removes all stopwords from an array of terms. If body stopwords are
* available, those will also be removed. The terms must be in the array values.
*
* @param array $terms An array of terms to clean out.
*
* @return array An array of terms with stopwords removed.
*/
function relevanssi_remove_stopwords_from_array( $terms ) {
$stopword_list = relevanssi_fetch_stopwords();
if ( function_exists( 'relevanssi_fetch_body_stopwords' ) ) {
$stopword_list = array_merge( $stopword_list, relevanssi_fetch_body_stopwords() );
}
$terms_without_stops = array_diff( $terms, $stopword_list );
return $terms_without_stops;
}
/**
* Updates the relevanssi_stopwords setting from a simple string to an array
* that is required for multilingual stopwords.
*/
function relevanssi_update_stopwords_setting() {
$stopwords = get_option( 'relevanssi_stopwords' );
if ( is_object( $stopwords ) ) {
$array_stopwords = (array) $stopwords;
update_option( 'relevanssi_stopwords', $array_stopwords );
return;
}
$current_language = relevanssi_get_current_language();
$array_stopwords[ $current_language ] = $stopwords;
update_option( 'relevanssi_stopwords', $array_stopwords );
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* /lib/tabs/attachments-tab.php
*
* Prints out the Attachments tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the attachments tab in Relevanssi settings.
*/
function relevanssi_attachments_tab() {
?>
<h2><?php esc_html_e( 'Indexing attachment content', 'relevanssi' ); ?></h2>
<p><?php esc_html_e( 'With Relevanssi Premium, you can index the text contents of attachments (PDFs, Word documents, Open Office documents and many other types). The contents of the attachments are processed on an external service, which makes the feature reliable and light on your own server performance.', 'relevanssi' ); ?></p>
<?php // Translators: %1$s starts the link, %2$s closes it. ?>
<p><?php printf( esc_html__( 'In order to access this and many other delightful Premium features, %1$sbuy Relevanssi Premium here%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/buy-premium/">', '</a>' ); ?></p>
<?php
}

View File

@@ -1,166 +0,0 @@
<?php
/**
* /lib/tabs/debugging-tab.php
*
* Prints out the Debugging tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the debugging tab in Relevanssi settings.
*/
function relevanssi_debugging_tab() {
$how_relevanssi_sees = '';
$db_post_view = '';
$current_post_id = 0;
$current_db_post_id = 0;
$selected = 'post';
if ( isset( $_REQUEST['post_id'] ) ) {
wp_verify_nonce( '_relevanssi_nonce', 'relevanssi_how_relevanssi_sees' );
$type = 'post';
if ( isset( $_REQUEST['type'] ) ) {
if ( 'term' === $_REQUEST['type'] ) {
$type = 'term';
$selected = 'term';
}
if ( 'user' === $_REQUEST['type'] ) {
$type = 'user';
$selected = 'user';
}
}
if ( intval( $_REQUEST['post_id'] ) > 0 ) {
$current_post_id = intval( $_REQUEST['post_id'] );
$how_relevanssi_sees = relevanssi_generate_how_relevanssi_sees(
intval( $current_post_id ),
true,
$type
);
}
}
if ( isset( $_REQUEST['db_post_id'] ) ) {
wp_verify_nonce( '_relevanssi_nonce', 'relevanssi_how_relevanssi_sees' );
if ( intval( $_REQUEST['db_post_id'] ) > 0 ) {
$current_db_post_id = intval( $_REQUEST['db_post_id'] );
$db_post_view = relevanssi_generate_db_post_view( $current_db_post_id );
}
}
wp_nonce_field( 'relevanssi_how_relevanssi_sees', '_relevanssi_nonce', true, true );
?>
<h2><?php esc_html_e( 'Debugging', 'relevanssi' ); ?></h2>
<p><?php esc_html_e( 'In order to figure out problems with indexing posts, you can test how Relevanssi sees the post by entering the post ID number in the field below.', 'relevanssi' ); ?></p>
<?php
if ( RELEVANSSI_PREMIUM ) {
?>
<p><?php esc_html_e( 'You can also check user profiles and taxonomy terms by choosing the type from the dropdown.', 'relevanssi' ); ?></p>
<?php
}
if ( ! RELEVANSSI_PREMIUM ) {
// Translators: %1$s starts the link, %2$s closes it.
printf( '<p>' . esc_html__( 'In Relevanssi Premium, you can find this feature for each post on the post edit page. %1$sBuy Relevanssi Premium here%2$s.', 'relevanssi' ) . '</p>', '<a href="https://www.relevanssi.com/buy-premium/">', '</a>' );
}
?>
<p><label for="post_id"><?php esc_html_e( 'The ID', 'relevanssi' ); ?></label>:
<input type="text" name="post_id" id="post_id"
<?php
if ( $current_post_id > 0 ) {
echo 'value="' . esc_attr( $current_post_id ) . '"';
}
?>
/>
<?php
if ( RELEVANSSI_PREMIUM ) {
?>
<select name="type">
<option value="post"
<?php if ( 'post' === $selected ) { ?>
selected="selected"
<?php } ?>><?php esc_html_e( 'Post', 'relevanssi' ); ?></option>
<option value="term"
<?php if ( 'term' === $selected ) { ?>
selected="selected"
<?php } ?>><?php esc_html_e( 'Taxonomy term', 'relevanssi' ); ?></option>
<option value="user"
<?php if ( 'user' === $selected ) { ?>
selected="selected"
<?php } ?>><?php esc_html_e( 'User', 'relevanssi' ); ?></option>
</select>
<?php
}
?>
</p>
<p>
<input
type='submit' name='submit'
value='<?php esc_attr_e( 'Check the post', 'relevanssi' ); ?>'
class='button button-primary' />
</p>
<?php echo $how_relevanssi_sees; // phpcs:ignore WordPress.Security.EscapeOutput ?>
<h2><?php esc_html_e( 'How does the post look like in the database?', 'relevanssi' ); ?></h2>
<p><?php esc_html_e( "This feature will show you how the post looks like in the database. It can sometimes be very helpful for debugging why a post isn't indexed the way you expect it to be.", 'relevanssi' ); ?></p>
<p><label for="db_post_id"><?php esc_html_e( 'The ID', 'relevanssi' ); ?></label>:
<input type="text" name="db_post_id" id="db_post_id"
<?php
if ( $current_db_post_id > 0 ) {
echo 'value="' . esc_attr( $current_db_post_id ) . '"';
}
?>
/>
</p>
<p>
<input
type='submit' name='submit'
value='<?php esc_attr_e( 'Check the post', 'relevanssi' ); ?>'
class='button button-primary' />
</p>
<?php echo $db_post_view; // phpcs:ignore WordPress.Security.EscapeOutput ?>
<h2><?php esc_html_e( 'Debugging information', 'relevanssi' ); ?></h2>
<?php
global $wpdb;
$max_allowed_packet = $wpdb->get_var( 'SELECT @@global.max_allowed_packet' );
$max_allowed_packet = round( $max_allowed_packet / 1024 / 1024, 2 );
echo '<p>max_allowed_packet: ' . $max_allowed_packet . 'M</p>'; // phpcs:ignore WordPress.Security.EscapeOutput
$indexing_query = relevanssi_generate_indexing_query(
relevanssi_valid_status_array(),
false,
relevanssi_post_type_restriction(),
0
);
?>
<p><?php esc_html_e( 'Indexing query', 'relevanssi' ); ?>:</p>
<?php
echo '<code>' . $indexing_query . '</code>'; // phpcs:ignore WordPress.Security.EscapeOutput
?>
<?php do_action( 'relevanssi_debugging_tab' ); ?>
<h2><?php esc_html_e( 'Debugging mode', 'relevanssi' ); ?></h2>
<?php
$enable_debugging_mode = relevanssi_check( get_option( 'relevanssi_debugging_mode' ) );
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Enable the debugging mode.', 'relevanssi' ); ?></legend>
<label for='relevanssi_debugging_mode'>
<input type='checkbox' name='relevanssi_debugging_mode' id='relevanssi_debugging_mode' <?php echo esc_html( $enable_debugging_mode ); ?> />
<?php esc_html_e( 'Enable the debugging mode.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( "Relevanssi support may ask you to enable the debugging mode. When you check this box, it's possible to see debugging information from the front-end.", 'relevanssi' ); ?></p>
</fieldset>
<?php
}

View File

@@ -1,428 +0,0 @@
<?php
/**
* /lib/tabs/excerpts-tab.php
*
* Prints out the Excerpts tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the excerpts tab in Relevanssi settings.
*/
function relevanssi_excerpts_tab() {
$excerpts = get_option( 'relevanssi_excerpts' );
$excerpt_length = get_option( 'relevanssi_excerpt_length' );
$excerpt_type = get_option( 'relevanssi_excerpt_type' );
$excerpt_allowable_tags = get_option( 'relevanssi_excerpt_allowable_tags' );
$excerpt_custom_fields = get_option( 'relevanssi_excerpt_custom_fields' );
$highlight = get_option( 'relevanssi_highlight' );
$txt_col = get_option( 'relevanssi_txt_col' );
$bg_col = get_option( 'relevanssi_bg_col' );
$css = get_option( 'relevanssi_css' );
$class = get_option( 'relevanssi_class' );
$highlight_title = get_option( 'relevanssi_hilite_title' );
$highlight_docs = get_option( 'relevanssi_highlight_docs' );
$highlight_coms = get_option( 'relevanssi_highlight_comments' );
$show_matches = get_option( 'relevanssi_show_matches' );
$show_matches_text = get_option( 'relevanssi_show_matches_text' );
$index_fields = get_option( 'relevanssi_index_fields' );
$expand_highlights = get_option( 'relevanssi_expand_highlights' );
if ( '#' !== substr( $txt_col, 0, 1 ) ) {
$txt_col = '#' . $txt_col;
}
$txt_col = relevanssi_sanitize_hex_color( $txt_col );
if ( '#' !== substr( $bg_col, 0, 1 ) ) {
$bg_col = '#' . $bg_col;
}
$bg_col = relevanssi_sanitize_hex_color( $bg_col );
$show_matches_text = stripslashes( $show_matches_text );
$excerpts = relevanssi_check( $excerpts );
$excerpt_custom_fields = relevanssi_check( $excerpt_custom_fields );
$highlight_title = relevanssi_check( $highlight_title );
$highlight_docs = relevanssi_check( $highlight_docs );
$highlight_coms = relevanssi_check( $highlight_coms );
$show_matches = relevanssi_check( $show_matches );
$expand_highlights = relevanssi_check( $expand_highlights );
$excerpt_chars = relevanssi_select( $excerpt_type, 'chars' );
$excerpt_words = relevanssi_select( $excerpt_type, 'words' );
$highlight_none = relevanssi_select( $highlight, 'no' );
$highlight_mark = relevanssi_select( $highlight, 'mark' );
$highlight_em = relevanssi_select( $highlight, 'em' );
$highlight_strong = relevanssi_select( $highlight, 'strong' );
$highlight_col = relevanssi_select( $highlight, 'col' );
$highlight_bgcol = relevanssi_select( $highlight, 'bgcol' );
$highlight_style = relevanssi_select( $highlight, 'css' );
$highlight_class = relevanssi_select( $highlight, 'class' );
$txt_col_display = 'screen-reader-text';
$bg_col_display = 'screen-reader-text';
$css_display = 'screen-reader-text';
$class_display = 'screen-reader-text';
if ( 'col' === $highlight ) {
$txt_col_display = '';
}
if ( 'bgcol' === $highlight ) {
$bg_col_display = '';
}
if ( 'css' === $highlight ) {
$css_display = '';
}
if ( 'class' === $highlight ) {
$class_display = '';
}
?>
<h2 id="excerpts"><?php esc_html_e( 'Custom excerpts/snippets', 'relevanssi' ); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<?php esc_html_e( 'Custom search result snippets', 'relevanssi' ); ?>
</th>
<td>
<label >
<input type='checkbox' name='relevanssi_excerpts' id='relevanssi_excerpts' <?php echo esc_html( $excerpts ); ?> />
<?php esc_html_e( 'Create custom search result snippets', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Only enable this if you actually use the custom excerpts.', 'relevanssi' ); ?></p>
<?php
$theme = wp_get_theme();
$template = $theme->get( 'Template' );
if ( 'divi' === strtolower( $template ) ) :
?>
<?php // Translators: %1$s opens the link, %2$s closes it. ?>
<p class="important"><?php printf( esc_html__( 'Looks like you are using Divi. In order to use custom excerpts with Divi, you need to make some changes to your templates. %1$sSee instructions here%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/knowledge-base/divi-page-builder-and-cleaner-excerpts/">', '</a>' ); ?></p>
<?php endif; ?>
</td>
</tr>
<tr id="tr_excerpt_length"
<?php
if ( empty( $excerpts ) ) {
echo "class='relevanssi_disabled'";
}
?>
>
<th scope="row">
<label for='relevanssi_excerpt_length'><?php esc_html_e( 'Length of the snippet', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='relevanssi_excerpt_length' id='relevanssi_excerpt_length' size='4' value='<?php echo esc_attr( $excerpt_length ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<label for="relevanssi_excerpt_type" class="screen-reader-text"><?php esc_html_e( 'Excerpt length type', 'relevanssi' ); ?></label>
<select name='relevanssi_excerpt_type' id='relevanssi_excerpt_type'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
>
<option value='chars' <?php echo esc_html( $excerpt_chars ); ?>><?php esc_html_e( 'characters', 'relevanssi' ); ?></option>
<option value='words' <?php echo esc_html( $excerpt_words ); ?>><?php esc_html_e( 'words', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( "Using words is much faster than characters. Don't use characters, unless you have a really good reason and your posts are short.", 'relevanssi' ); ?></p>
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_max_excerpts' ) ) {
relevanssi_form_max_excerpts( $excerpts );
}
?>
<tr id="tr_excerpt_allowable_tags"
<?php
if ( empty( $excerpts ) ) {
echo "class='relevanssi_disabled'";
}
?>
>
<th scope="row">
<label for='relevanssi_excerpt_allowable_tags'><?php esc_html_e( 'Allowable tags in excerpts', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='relevanssi_excerpt_allowable_tags' id='relevanssi_excerpt_allowable_tags' size='60' value='<?php echo esc_attr( $excerpt_allowable_tags ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<p class="description"><?php esc_html_e( 'List all tags you want to allow in excerpts. For example: &lt;p&gt;&lt;a&gt;&lt;strong&gt;.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr id="tr_excerpt_custom_fields"
<?php
if ( empty( $excerpts ) ) {
echo "class='relevanssi_disabled'";
}
?>
>
<th scope="row">
<?php esc_html_e( 'Use custom fields for excerpts', 'relevanssi' ); ?>
</th>
<td>
<label>
<input type='checkbox' name='relevanssi_excerpt_custom_fields' id='relevanssi_excerpt_custom_fields' <?php echo esc_html( $excerpt_custom_fields ); ?>
<?php
if ( empty( $excerpts ) || empty( $index_fields ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Use custom field content for building excerpts', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Use the custom fields setting for indexing for excerpt-making as well. Enabling this option will show custom field content in Relevanssi-generated excerpts.', 'relevanssi' ); ?>
<?php
if ( RELEVANSSI_PREMIUM ) {
esc_html_e( 'Enable this option to use PDF content for excerpts.', 'relevanssi' );
}
?>
</p>
<p class="description"><?php esc_html_e( 'Current custom field setting', 'relevanssi' ); ?>:
<?php
if ( 'visible' === $index_fields ) {
esc_html_e( 'all visible custom fields', 'relevanssi' );
} elseif ( 'all' === $index_fields ) {
esc_html_e( 'all custom fields', 'relevanssi' );
} elseif ( ! empty( $index_fields ) ) {
printf( '<code>%s</code>', esc_html( $index_fields ) );
} elseif ( RELEVANSSI_PREMIUM ) {
esc_html_e( 'Just PDF content', 'relevanssi' );
} else {
esc_html_e( 'None selected', 'relevanssi' );
}
?>
</p>
</td>
</tr>
</table>
<h2><?php esc_html_e( 'Search hit highlighting', 'relevanssi' ); ?></h2>
<table id="relevanssi_highlighting" class="form-table
<?php
if ( empty( $excerpts ) ) {
echo 'relevanssi_disabled';
}
?>
" role="presentation">
<tr>
<th scope="row">
<label for='relevanssi_highlight'><?php esc_html_e( 'Highlight type', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_highlight' id='relevanssi_highlight'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
>
<option value='no' <?php echo esc_html( $highlight_none ); ?>><?php esc_html_e( 'No highlighting', 'relevanssi' ); ?></option>
<option value='mark' <?php echo esc_html( $highlight_mark ); ?>>&lt;mark&gt;</option>
<option value='em' <?php echo esc_html( $highlight_em ); ?>>&lt;em&gt;</option>
<option value='strong' <?php echo esc_html( $highlight_strong ); ?>>&lt;strong&gt;</option>
<option value='col' <?php echo esc_html( $highlight_col ); ?>><?php esc_html_e( 'Text color', 'relevanssi' ); ?></option>
<option value='bgcol' <?php echo esc_html( $highlight_bgcol ); ?>><?php esc_html_e( 'Background color', 'relevanssi' ); ?></option>
<option value='css' <?php echo esc_html( $highlight_style ); ?>><?php esc_html_e( 'CSS Style', 'relevanssi' ); ?></option>
<option value='class' <?php echo esc_html( $highlight_class ); ?>><?php esc_html_e( 'CSS Class', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'Requires custom snippets to work.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr id="tr_relevanssi_txt_col" class='<?php echo esc_attr( $txt_col_display ); ?>'>
<th scope="row">
<?php esc_html_e( 'Text color', 'relevanssi' ); ?>
</th>
<td>
<input type='text' name='relevanssi_txt_col' id='relevanssi_txt_col' size='7' class="color-field" data-default-color="#ff0000" value='<?php echo esc_attr( $txt_col ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
</td>
</tr>
<tr id="tr_relevanssi_bg_col" class=' <?php echo esc_attr( $bg_col_display ); ?>'>
<th scope="row">
<?php esc_html_e( 'Background color', 'relevanssi' ); ?>
</th>
<td>
<input type='text' name='relevanssi_bg_col' id='relevanssi_bg_col' size='7' class="color-field" data-default-color="#ffaf75" value='<?php echo esc_attr( $bg_col ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
</td>
</tr>
<tr id="tr_relevanssi_css" class=' <?php echo esc_attr( $css_display ); ?>'>
<th scope="row">
<label for='relevanssi_css'><?php esc_html_e( 'CSS style for highlights', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='relevanssi_css' id='relevanssi_css' size='60' value='<?php echo esc_attr( $css ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php // Translators: %s is a <span> tag. ?>
<p class="description"><?php printf( esc_html__( 'The highlights will be wrapped in a %s with this CSS in the style parameter.', 'relevanssi' ), '&lt;span&gt;' ); ?></p>
</td>
</tr>
<tr id="tr_relevanssi_class" class=' <?php echo esc_attr( $class_display ); ?>'>
<th scope="row">
<label for='relevanssi_class'><?php esc_html_e( 'CSS class for highlights', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='relevanssi_class' id='relevanssi_class' size='60' value='<?php echo esc_attr( $class ); ?>'
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php // Translators: %s is a <span> tag. ?>
<p class="description"><?php printf( esc_html__( 'The highlights will be wrapped in a %s with this class.', 'relevanssi' ), '&lt;span&gt;' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Highlight in titles', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_hilite_title'>
<input type='checkbox' name='relevanssi_hilite_title' id='relevanssi_hilite_title' <?php echo esc_html( $highlight_title ); ?>
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Highlight query terms in titles', 'relevanssi' ); ?>
</label>
<?php // Translators: %1$s is 'the_title()', %2$s is 'relevanssi_the_title()'. ?>
<p class="description"><?php printf( esc_html__( 'Highlights in titles require changes to the search results template. You need to replace %1$s in the search results template with %2$s. For more information, see the contextual help.', 'relevanssi' ), '<code>the_title()</code>', '<code>relevanssi_the_title()</code>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Highlight in documents', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_highlight_docs'>
<input type='checkbox' name='relevanssi_highlight_docs' id='relevanssi_highlight_docs' <?php echo esc_html( $highlight_docs ); ?>
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Highlight query terms in documents', 'relevanssi' ); ?>
</label>
<?php // Translators: %s is 'highlight'. ?>
<p class="description"><?php printf( esc_html__( 'Highlights hits when user opens the post from search results. This requires an extra parameter (%s) to the links from the search results pages, which Relevanssi should add automatically.', 'relevanssi' ), '<code>highlight</code>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Highlight in comments', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_highlight_comments'>
<input type='checkbox' name='relevanssi_highlight_comments' id='relevanssi_highlight_comments' <?php echo esc_html( $highlight_coms ); ?>
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Highlight query terms in comments', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Highlights hits in comments when user opens the post from search results.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Expand highlights', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_expand_highlights'>
<input type='checkbox' name='relevanssi_expand_highlights' id='relevanssi_expand_highlights' <?php echo esc_html( $expand_highlights ); ?>
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Expand highlights to cover full words', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'When a highlight matches part of the word, if this option is enabled, the highlight will be expanded to highlight the whole word.', 'relevanssi' ); ?></p>
</td>
</tr>
</table>
<h2><?php esc_html_e( 'Breakdown of search results', 'relevanssi' ); ?></h2>
<table id="relevanssi_breakdown" class="form-table
<?php
if ( empty( $excerpts ) ) {
echo 'relevanssi_disabled';
}
?>
" role="presentation">
<tr>
<th scope="row">
<?php esc_html_e( 'Breakdown of search hits in excerpts', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_show_matches'>
<input type='checkbox' name='relevanssi_show_matches' id='relevanssi_show_matches' <?php echo esc_html( $show_matches ); ?>
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
/>
<?php esc_html_e( 'Show the breakdown of search hits in the excerpts.', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Requires custom snippets to work.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_show_matches_text'><?php esc_html_e( 'The breakdown format', 'relevanssi' ); ?></label>
</th>
<td>
<textarea name='relevanssi_show_matches_text' id='relevanssi_show_matches_text' cols="80" rows="4"
<?php
if ( empty( $excerpts ) ) {
echo "disabled='disabled'";
}
?>
><?php echo esc_attr( $show_matches_text ); ?></textarea>
<p class="description"><?php esc_html_e( 'Use %body%, %title%, %categories%, %tags%, %taxonomies%, %comments%, %customfields%, %author%, %excerpt% and %mysqlcolumns% to display the number of hits (in different parts of the post), %total% for total hits, %score% to display the document weight and %terms% to show how many hits each search term got.', 'relevanssi' ); /* phpcs:ignore WordPress.WP.I18n */ ?></p>
</td>
</tr>
</table>
<?php
}

View File

@@ -1,529 +0,0 @@
<?php
/**
* /lib/tabs/indexing-tab.php
*
* Prints out the Indexing tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the indexing tab in Relevanssi settings.
*
* @global $wpdb The WordPress database interface.
* @global $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_indexing_tab() {
global $wpdb, $relevanssi_variables;
$index_post_types = get_option( 'relevanssi_index_post_types' );
$index_taxonomies_list = get_option( 'relevanssi_index_taxonomies_list' );
$index_comments = get_option( 'relevanssi_index_comments' );
$index_fields = get_option( 'relevanssi_index_fields' );
$index_author = get_option( 'relevanssi_index_author' );
$index_excerpt = get_option( 'relevanssi_index_excerpt' );
$index_image_files = get_option( 'relevanssi_index_image_files' );
$expand_shortcodes = get_option( 'relevanssi_expand_shortcodes' );
$punctuation = get_option( 'relevanssi_punctuation' );
$min_word_length = get_option( 'relevanssi_min_word_length' );
if ( empty( $index_post_types ) ) {
$index_post_types = array();
}
if ( empty( $index_taxonomies_list ) ) {
$index_taxonomies_list = array();
}
$expand_shortcodes = relevanssi_check( $expand_shortcodes );
$index_author = relevanssi_check( $index_author );
$index_excerpt = relevanssi_check( $index_excerpt );
$index_image_files = relevanssi_check( $index_image_files );
$index_comments_all = relevanssi_select( $index_comments, 'all' );
$index_comments_normal = relevanssi_select( $index_comments, 'normal' );
$index_comments_none = relevanssi_select( $index_comments, 'none' );
$fields_select_all = '';
$fields_select_none = '';
$fields_select_some = 'selected';
$fields_select_visible = '';
if ( empty( $index_fields ) ) {
$fields_select_none = 'selected';
$fields_select_some = '';
}
if ( 'all' === $index_fields ) {
$fields_select_all = 'selected';
$fields_select_some = '';
$index_fields = '';
}
if ( 'visible' === $index_fields ) {
$fields_select_visible = 'selected';
$fields_select_some = '';
$index_fields = '';
}
if ( ! isset( $punctuation['quotes'] ) ) {
$punctuation['quotes'] = 'replace';
}
if ( ! isset( $punctuation['decimals'] ) ) {
$punctuation['decimals'] = 'remove';
}
if ( ! isset( $punctuation['ampersands'] ) ) {
$punctuation['ampersands'] = 'replace';
}
if ( ! isset( $punctuation['hyphens'] ) ) {
$punctuation['hyphens'] = 'replace';
}
$punct_quotes_replace = relevanssi_select( $punctuation['quotes'], 'replace' );
$punct_quotes_remove = relevanssi_select( $punctuation['quotes'], 'remove' );
$punct_decimals_replace = relevanssi_select( $punctuation['decimals'], 'replace' );
$punct_decimals_remove = relevanssi_select( $punctuation['decimals'], 'remove' );
$punct_decimals_keep = relevanssi_select( $punctuation['decimals'], 'keep' );
$punct_ampersands_replace = relevanssi_select( $punctuation['ampersands'], 'replace' );
$punct_ampersands_remove = relevanssi_select( $punctuation['ampersands'], 'remove' );
$punct_ampersands_keep = relevanssi_select( $punctuation['ampersands'], 'keep' );
$punct_hyphens_replace = relevanssi_select( $punctuation['hyphens'], 'replace' );
$punct_hyphens_remove = relevanssi_select( $punctuation['hyphens'], 'remove' );
$punct_hyphens_keep = relevanssi_select( $punctuation['hyphens'], 'keep' );
$docs_count = get_option( 'relevanssi_doc_count', 0 );
$terms_count = get_option( 'relevanssi_terms_count', 0 );
$lowest_doc = $wpdb->get_var( 'SELECT doc FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc > 0 ORDER BY doc ASC LIMIT 1' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
if ( null === $lowest_doc ) {
// The database table is empty or doesn't exist.
$lowest_doc = 0;
relevanssi_create_database_tables( 0 );
}
if ( RELEVANSSI_PREMIUM ) {
$user_count = get_option( 'relevanssi_user_count', 0 );
$taxterm_count = get_option( 'relevanssi_taxterm_count', 0 );
}
$this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
$update_url = wp_nonce_url( $this_page . '&tab=indexing&update_counts=1', 'update_counts' );
?>
<div id="indexing_tab">
<table class="form-table" role="presentation">
<tr>
<td scope="row">
<input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' /><br /><br />
<input type="button" id="build_index" name="index" value="<?php esc_attr_e( 'Build the index', 'relevanssi' ); ?>" class='button-primary' /><br /><br />
<input type="button" id="continue_indexing" name="continue" value="<?php esc_attr_e( 'Index unindexed posts', 'relevanssi' ); ?>" class='button-primary' />
</td>
<td>
<div id='indexing_button_instructions'>
<?php // Translators: %s is "Build the index". ?>
<p class="description"><?php printf( esc_html__( '%s empties the existing index and rebuilds it from scratch.', 'relevanssi' ), '<strong>' . esc_html__( 'Build the index', 'relevanssi' ) . '</strong>' ); ?></p>
<?php // Translators: %s is "Build the index". ?>
<p class="description"><?php printf( esc_html__( "%s doesn't empty the index and only indexes those posts that are not indexed. You can use it if you have to interrupt building the index.", 'relevanssi' ), '<strong>' . esc_html__( 'Index unindexed posts', 'relevanssi' ) . '</strong>' ); ?>
<?php
if ( RELEVANSSI_PREMIUM ) {
esc_html_e( "This doesn't index any taxonomy terms or users.", 'relevanssi' );
}
?>
</p>
</div>
<div id='relevanssi-note' style='display: none'></div>
<div id='relevanssi-progress' class='rpi-progress'><div class="rpi-indicator"></div></div>
<div id='relevanssi-timer'><?php esc_html_e( 'Time elapsed', 'relevanssi' ); ?>: <span id="relevanssi_elapsed">0:00:00</span> | <?php esc_html_e( 'Time remaining', 'relevanssi' ); ?>: <span id="relevanssi_estimated"><?php esc_html_e( 'some time', 'relevanssi' ); ?></span></div>
<label for="results" class="screen-reader-text"><?php esc_html_e( 'Results', 'relevanssi' ); ?></label><textarea id='results' rows='10' cols='80'></textarea>
<div id='relevanssi-indexing-instructions' style='display: none'><?php esc_html_e( "Indexing should respond quickly. If nothing happens in couple of minutes, it's probably stuck. The most common reasons for indexing issues are incompatible shortcodes, so try disabling the shortcode expansion setting and try again. Also, if you've just updated Relevanssi, doing a hard refresh in your browser will make sure your browser is not trying to use an outdated version of the Relevanssi scripts.", 'relevanssi' ); ?></div>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'State of the index', 'relevanssi' ); ?></td>
<td id="stateoftheindex"><p><?php echo esc_html( $docs_count ); ?> <?php echo esc_html( _n( 'document in the index.', 'documents in the index.', $docs_count, 'relevanssi' ) ); ?>
<?php if ( RELEVANSSI_PREMIUM ) : ?>
<br /><?php echo esc_html( $user_count ); ?> <?php echo esc_html( _n( 'user in the index.', 'users in the index.', $user_count, 'relevanssi' ) ); ?><br />
<?php echo esc_html( $taxterm_count ); ?> <?php echo esc_html( _n( 'taxonomy term in the index.', 'taxonomy terms in the index.', $taxterm_count, 'relevanssi' ) ); ?>
<?php endif; ?>
</p>
<p><?php echo esc_html( $terms_count ); ?> <?php echo esc_html( _n( 'term in the index.', 'terms in the index.', $terms_count, 'relevanssi' ) ); ?><br />
<?php echo esc_html( $lowest_doc ); ?> <?php esc_html_e( 'is the lowest post ID indexed.', 'relevanssi' ); ?></p>
<?php /* Translators: %1$s opens the a tag, %2$s closes it. */ ?>
<p class="description">(<?php printf( esc_html__( 'These values may be inaccurate. If you need exact values, %1$supdate the counts%2$s', 'relevanssi' ), '<a href="' . esc_attr( $update_url ) . '">', '</a>' ); ?>.)</p>
</td>
</tr>
</table>
<?php
if ( count( $index_post_types ) < 2 ) {
$index_users = get_option( 'relevanssi_index_users', 'off' );
$index_taxonomies = get_option( 'relevanssi_index_taxonomies', 'off' );
if ( 'off' === $index_users && 'off' === $index_taxonomies ) {
printf( '<p><strong>%s</strong></p>', esc_html__( "WARNING: You've chosen no post types to index. Nothing will be indexed. Choose some post types to index.", 'relevanssi' ) );
}
}
?>
<h2 id="indexing"><?php esc_html_e( 'Indexing options', 'relevanssi' ); ?></h2>
<p><?php esc_html_e( 'Any changes to the settings on this page require reindexing before they take effect.', 'relevanssi' ); ?></p>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><?php esc_html_e( 'Post types', 'relevanssi' ); ?></th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Post types to index', 'relevanssi' ); ?></legend>
<table class="widefat" id="index_post_types_table">
<thead>
<tr>
<th><?php esc_html_e( 'Type', 'relevanssi' ); ?></th>
<th><?php esc_html_e( 'Index', 'relevanssi' ); ?></th>
<th><?php esc_html_e( 'Excluded from search?', 'relevanssi' ); ?></th>
</tr>
</thead>
<?php
$pt_1 = get_post_types( array( 'exclude_from_search' => '0' ) );
$pt_2 = get_post_types( array( 'exclude_from_search' => false ) );
$public_types = array_merge( $pt_1, $pt_2 );
$post_types = get_post_types();
foreach ( $post_types as $type ) {
if ( in_array( $type, relevanssi_get_forbidden_post_types(), true ) ) {
continue;
}
$checked = '';
if ( in_array( $type, $index_post_types, true ) ) {
$checked = 'checked="checked"';
}
// Translators: %s is the post type name.
$screen_reader_label = sprintf( __( 'Index post type %s', 'relevanssi' ), $type );
$label = $type;
$excluded_from_search = __( 'yes', 'relevanssi' );
// Translators: %s is the post type name.
$screen_reader_exclude = sprintf( __( 'Post type %s is excluded from search', 'relevanssi' ), $type );
if ( in_array( $type, $public_types, true ) ) {
$excluded_from_search = __( 'no', 'relevanssi' );
// Translators: %s is the post type name.
$screen_reader_exclude = sprintf( __( 'Post type %s can be searched', 'relevanssi' ), $type );
}
$name_id = 'relevanssi_index_type_' . $type;
printf(
'<tr>
<th scope="row"><label class="screen-reader-text" for="%3$s">%1$s</label> %2$s</th>
<td><input type="checkbox" name="%3$s" id="%3$s" %4$s /></td>
<td><span aria-hidden="true">%5$s</span><span class="screen-reader-text">%6$s</span></td>
</tr>',
esc_html( $screen_reader_label ),
esc_html( $label ),
esc_attr( $name_id ),
esc_html( $checked ),
esc_html( $excluded_from_search ),
esc_html( $screen_reader_exclude )
);
}
?>
<tr style="display:none">
<td>
<label for="relevanssi_index_type_bogus">Helper control field to make sure settings are saved if no post types are selected.</label>
</td>
<td>
<input type='checkbox' name='relevanssi_index_type_bogus' id='relevanssi_index_type_bogus' checked="checked" />
</td>
<td>
This is our little secret, just for you and me
</td>
</tr>
</table>
</fieldset>
<p class="description"><?php esc_html_e( "If you want to index a post type that's marked 'Excluded from search', you can do that without worrying about it but you need to uncheck the 'Respect exclude_from_search' setting from the Searching tab.", 'relevanssi' ); ?></p>
</td>
</tr>
<tr id="row_index_image_files"
<?php
if ( ! in_array( 'attachment', $index_post_types, true ) ) {
echo 'style="display: none"';
}
?>
>
<th scope="row">
<?php esc_html_e( 'Index image files', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_index_image_files'>
<input type='checkbox' name='relevanssi_index_image_files' id='relevanssi_index_image_files' <?php echo esc_attr( $index_image_files ); ?> />
<?php esc_html_e( 'Index image attachments', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'If this option is enabled, Relevanssi will include image attachments in the index. If the option is disabled, only other attachment types are included.', 'relevanssi' ); ?></p>
<?php // Translators: %1$s opens the link, %2$s closes it. ?>
<p class="description"><?php printf( esc_html__( 'For more detailed control over the attachment type indexing, see %1$sControlling attachment types in the Knowledge base%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/knowledge-base/controlling-attachment-types-index/">', '</a>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Taxonomies', 'relevanssi' ); ?>
</th>
<td>
<table class="widefat" id="custom_taxonomies_table">
<thead>
<tr>
<th><?php esc_html_e( 'Taxonomy', 'relevanssi' ); ?></th>
<th><?php esc_html_e( 'Index', 'relevanssi' ); ?></th>
<th><?php esc_html_e( 'Public?', 'relevanssi' ); ?></th>
</tr>
</thead>
<?php
$taxos = get_taxonomies( '', 'objects' );
foreach ( $taxos as $taxonomy ) {
if ( in_array( $taxonomy->name, relevanssi_get_forbidden_taxonomies(), true ) ) {
continue;
}
$checked = '';
if ( in_array( $taxonomy->name, $index_taxonomies_list, true ) ) {
$checked = 'checked="checked"';
}
// Translators: %s is the taxonomy name.
$screen_reader_label = sprintf( __( 'Index taxonomy %s', 'relevanssi' ), $taxonomy->name );
$public = __( 'no', 'relevanssi' );
// Translators: %s is the taxonomy name.
$screen_reader_public = sprintf( __( 'Taxonomy %s is not public', 'relevanssi' ), $taxonomy->name );
if ( $taxonomy->public ) {
$public = __( 'yes', 'relevanssi' );
// Translators: %s is the taxonomy name.
$screen_reader_public = sprintf( __( 'Taxonomy %s is public', 'relevanssi' ), $taxonomy->name );
}
$name_id = 'relevanssi_index_taxonomy_' . $taxonomy->name;
printf(
'<tr>
<th scope="row"><label class="screen-reader-text" for="%3$s">%1$s</label> %2$s</th>
<td><input type="checkbox" name="%3$s" id="%3$s" %4$s /></td>
<td><span aria-hidden="true">%5$s</span><span class="screen-reader-text">%6$s</span></td>
</tr>',
esc_html( $screen_reader_label ),
esc_html( $taxonomy->name ),
esc_attr( $name_id ),
esc_html( $checked ),
esc_html( $public ),
esc_html( $screen_reader_public )
);
}
?>
</table>
<p class="description"><?php esc_html_e( 'If you check a taxonomy here, the terms for that taxonomy are indexed with the posts. If you for example choose "post_tag", searching for a tag will find all posts that have the tag.', 'relevanssi' ); ?>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_index_comments'><?php esc_html_e( 'Comments', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_index_comments' id='relevanssi_index_comments'>
<option value='none' <?php echo esc_html( $index_comments_none ); ?>><?php esc_html_e( 'none', 'relevanssi' ); ?></option>
<option value='normal' <?php echo esc_html( $index_comments_normal ); ?>><?php esc_html_e( 'comments', 'relevanssi' ); ?></option>
<option value='all' <?php echo esc_html( $index_comments_all ); ?>><?php esc_html_e( 'comments and pingbacks', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'If you choose to index comments, you can choose if you want to index just comments, or everything including comments and track- and pingbacks.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_index_fields_select'><?php esc_html_e( 'Custom fields', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_index_fields_select' id='relevanssi_index_fields_select'>
<option value='none' <?php echo esc_html( $fields_select_none ); ?>><?php esc_html_e( 'none', 'relevanssi' ); ?></option>
<option value='all' <?php echo esc_html( $fields_select_all ); ?>><?php esc_html_e( 'all', 'relevanssi' ); ?></option>
<option value='visible' <?php echo esc_html( $fields_select_visible ); ?>><?php esc_html_e( 'visible', 'relevanssi' ); ?></option>
<option value='some' <?php echo esc_html( $fields_select_some ); ?>><?php esc_html_e( 'some', 'relevanssi' ); ?></option>
</select>
<p class="description">
<?php
esc_html_e( "'All' indexes all custom fields for posts.", 'relevanssi' );
echo '<br/>';
esc_html_e( "'Visible' only includes the custom fields that are visible in the user interface (with names that don't start with an underscore).", 'relevanssi' );
echo '<br/>';
esc_html_e( "'Some' lets you choose individual custom fields to index.", 'relevanssi' );
?>
</p>
<?php
if ( class_exists( 'acf' ) && $fields_select_all ) {
echo "<p class='description important'>";
esc_html_e( 'Advanced Custom Fields has lots of invisible custom fields with meta data. Selecting "all" will include lots of garbage in the index and excerpts. "Visible" is usually a better option with ACF.' );
echo '</p>';
}
?>
<div id="index_field_input"
<?php
if ( empty( $fields_select_some ) ) {
echo 'style="display: none"';
}
?>
>
<label for="relevanssi_index_fields" class="screen-reader-text"><?php esc_html_e( 'Custom fields to index', 'relevanssi' ); ?></label>
<input type='text' name='relevanssi_index_fields' id='relevanssi_index_fields' size='60' value='<?php echo esc_attr( $index_fields ); ?>' />
<p class="description"><?php esc_html_e( "Enter a comma-separated list of custom fields to include in the index. With Relevanssi Premium, you can also use 'fieldname_%_subfieldname' notation for ACF repeater fields.", 'relevanssi' ); ?></p>
<p class="description"><?php esc_html_e( "You can use 'relevanssi_index_custom_fields' filter hook to adjust which custom fields are indexed.", 'relevanssi' ); ?></p>
</div>
<?php if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) : ?>
<?php // Translators: %1$s is the 'some' option and %2$s is '_sku'. ?>
<p class="description"><?php printf( esc_html__( 'If you want the SKU included, choose %1$s and enter %2$s. Also see the contextual help for more details.', 'relevanssi' ), esc_html( "'" . __( 'some', 'relevanssi' ) . "'" ), '<code>_sku</code>' ); ?></p>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Author display names', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_index_author'>
<input type='checkbox' name='relevanssi_index_author' id='relevanssi_index_author' <?php echo esc_html( $index_author ); ?> />
<?php esc_html_e( 'Index the post author display name', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Searching for the post author display name will return posts by that author.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Excerpts', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_index_excerpt'>
<input type='checkbox' name='relevanssi_index_excerpt' id='relevanssi_index_excerpt' <?php echo esc_html( $index_excerpt ); ?> />
<?php esc_html_e( 'Index the post excerpt', 'relevanssi' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Relevanssi will find posts by the content in the excerpt.', 'relevanssi' ); ?></p>
<?php if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) : ?>
<p class="description"><?php esc_html_e( "WooCommerce stores the product short description in the excerpt, so it's a good idea to index excerpts.", 'relevanssi' ); ?></p>
<?php endif; ?>
</td>
</tr>
</table>
<h2><?php esc_html_e( 'Shortcodes', 'relevanssi' ); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<?php esc_html_e( 'Expand shortcodes', 'relevanssi' ); ?>
</th>
<td>
<label for='relevanssi_expand_shortcodes'>
<input type='checkbox' name='relevanssi_expand_shortcodes' id='relevanssi_expand_shortcodes' <?php echo esc_html( $expand_shortcodes ); ?> />
<?php esc_html_e( 'Expand shortcodes when indexing', 'relevanssi' ); ?>
</label>
<?php if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) : ?>
<p class="description important"><?php esc_html_e( "WooCommerce has shortcodes that don't work well with Relevanssi. With WooCommerce, make sure the option is disabled.", 'relevanssi' ); ?></p>
<?php endif; ?>
<p class="description"><?php esc_html_e( 'If checked, Relevanssi will expand shortcodes in post content before indexing. Otherwise shortcodes will be stripped.', 'relevanssi' ); ?></p>
<p class="description"><?php esc_html_e( 'If you use shortcodes to include dynamic content, Relevanssi will not keep the index updated, the index will reflect the status of the shortcode content at the moment of indexing.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
do_action( 'relevanssi_indexing_tab_shortcodes' );
?>
</table>
<?php
do_action( 'relevanssi_indexing_tab' );
?>
<h2><?php esc_html_e( 'Advanced indexing settings', 'relevanssi' ); ?></h2>
<p><button type="button" id="show_advanced_indexing"><?php esc_html_e( 'Show advanced settings', 'relevanssi' ); ?></button></p>
<table class="form-table screen-reader-text" id="advanced_indexing" role="presentation">
<tr>
<th scope="row">
<label for='relevanssi_min_word_length'><?php esc_html_e( 'Minimum word length', 'relevanssi' ); ?></label>
</th>
<td>
<input type='number' name='relevanssi_min_word_length' id='relevanssi_min_word_length' value='<?php echo esc_attr( $min_word_length ); ?>' />
<p class="description"><?php esc_html_e( 'Words shorter than this many letters will not be indexed.', 'relevanssi' ); ?></p>
<?php // Translators: %1$s is 'relevanssi_block_one_letter_searches' and %2$s is 'false'. ?>
<p class="description"><?php printf( esc_html__( 'To enable one-letter searches, you need to add a filter function on the filter hook %1$s that returns %2$s.', 'relevanssi' ), '<code>relevanssi_block_one_letter_searches</code>', '<code>false</code>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Punctuation control', 'relevanssi' ); ?></th>
<td><p class="description"><?php esc_html_e( 'Here you can adjust how the punctuation is controlled. For more information, see help. Remember that any changes here require reindexing, otherwise searches will fail to find posts they should.', 'relevanssi' ); ?></p></td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_punct_hyphens'><?php esc_html_e( 'Hyphens and dashes', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_punct_hyphens' id='relevanssi_punct_hyphens'>
<option value='keep' <?php echo esc_html( $punct_hyphens_keep ); ?>><?php esc_html_e( 'Keep', 'relevanssi' ); ?></option>
<option value='replace' <?php echo esc_html( $punct_hyphens_replace ); ?>><?php esc_html_e( 'Replace with spaces', 'relevanssi' ); ?></option>
<option value='remove' <?php echo esc_html( $punct_hyphens_remove ); ?>><?php esc_html_e( 'Remove', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'How Relevanssi should handle hyphens and dashes (en and em dashes)? Replacing with spaces is generally the best option, but in some cases removing completely is the best option. Keeping them is rarely the best option.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_punct_quotes'><?php esc_html_e( 'Apostrophes and quotes', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_punct_quotes' id='relevanssi_punct_quotes'>
<option value='replace' <?php echo esc_html( $punct_quotes_replace ); ?>><?php esc_html_e( 'Replace with spaces', 'relevanssi' ); ?></option>
<option value='remove' <?php echo esc_html( $punct_quotes_remove ); ?>><?php esc_html_e( 'Remove', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( "How Relevanssi should handle apostrophes and quotes? It's not possible to keep them; that would lead to problems. Default behaviour is to replace with spaces, but sometimes removing makes sense.", 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_punct_ampersands'><?php esc_html_e( 'Ampersands', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_punct_ampersands' id='relevanssi_punct_ampersands'>
<option value='keep' <?php echo esc_html( $punct_ampersands_keep ); ?>><?php esc_html_e( 'Keep', 'relevanssi' ); ?></option>
<option value='replace' <?php echo esc_html( $punct_ampersands_replace ); ?>><?php esc_html_e( 'Replace with spaces', 'relevanssi' ); ?></option>
<option value='remove' <?php echo esc_html( $punct_ampersands_remove ); ?>><?php esc_html_e( 'Remove', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'How Relevanssi should handle ampersands? Replacing with spaces is generally the best option, but if you talk a lot about D&amp;D, for example, keeping the ampersands is useful.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_punct_decimals'><?php esc_html_e( 'Decimal separators', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_punct_decimals' id='relevanssi_punct_decimals'>
<option value='keep' <?php echo esc_html( $punct_decimals_keep ); ?>><?php esc_html_e( 'Keep', 'relevanssi' ); ?></option>
<option value='replace' <?php echo esc_html( $punct_decimals_replace ); ?>><?php esc_html_e( 'Replace with spaces', 'relevanssi' ); ?></option>
<option value='remove' <?php echo esc_html( $punct_decimals_remove ); ?>><?php esc_html_e( 'Remove', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'How Relevanssi should handle periods between decimals? Replacing with spaces is the default option, but that often leads to the numbers being removed completely. If you need to search decimal numbers a lot, keep the periods.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
do_action( 'relevanssi_indexing_tab_advanced' );
?>
</table>
<p><button type="button" style="display: none" id="hide_advanced_indexing"><?php esc_html_e( 'Hide advanced settings', 'relevanssi' ); ?></button></p>
</div>
<?php
}

View File

@@ -1,126 +0,0 @@
<?php
/**
* /lib/tabs/logging-tab.php
*
* Prints out the Logging tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the logging tab in Relevanssi settings.
*
* @global $wpdb The WordPress database interface.
*/
function relevanssi_logging_tab() {
global $wpdb;
$log_queries = get_option( 'relevanssi_log_queries' );
$log_queries = relevanssi_check( $log_queries );
$log_queries_with_ip = get_option( 'relevanssi_log_queries_with_ip' );
$log_queries_with_ip = relevanssi_check( $log_queries_with_ip );
$omit_from_logs = get_option( 'relevanssi_omit_from_logs' );
$trim_logs = get_option( 'relevanssi_trim_logs' );
?>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<?php esc_html_e( 'Enable logs', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Keep a log of user queries.', 'relevanssi' ); ?></legend>
<label for='relevanssi_log_queries'>
<input type='checkbox' name='relevanssi_log_queries' id='relevanssi_log_queries' <?php echo esc_html( $log_queries ); ?> />
<?php esc_html_e( 'Keep a log of user queries.', 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description">
<?php
// Translators: %1$s is the name of the "User searches" page, %2$s is the name of the database table.
printf(
esc_html__( "If enabled, Relevanssi will log user queries. The logs can be examined under '%1\$s' on the Dashboard admin menu and are stored in the %2\$s database table.", 'relevanssi' ),
esc_html__( 'User searches', 'relevanssi' ),
esc_html( $wpdb->prefix . 'relevanssi_log' )
);
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Log user IP', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( "Log the user's IP with the queries.", 'relevanssi' ); ?></legend>
<label for='relevanssi_log_queries_with_ip'>
<input type='checkbox' name='relevanssi_log_queries_with_ip' id='relevanssi_log_queries_with_ip' <?php echo esc_html( $log_queries_with_ip ); ?> />
<?php esc_html_e( "Log the user's IP with the queries.", 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description"><?php esc_html_e( "If enabled, Relevanssi will log user's IP adress with the queries. Note that this may be illegal where you live, and in EU will create a person registry that falls under the GDPR.", 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_omit_from_logs'><?php esc_html_e( 'Exclude users', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='relevanssi_omit_from_logs' id='relevanssi_omit_from_logs' size='60' value='<?php echo esc_attr( $omit_from_logs ); ?>' />
<p class="description"><?php esc_html_e( 'Comma-separated list of numeric user IDs or user login names that will not be logged.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_hide_branding' ) ) {
relevanssi_form_hide_branding();
}
?>
<tr>
<th scope="row">
<label for='relevanssi_trim_logs'><?php esc_html_e( 'Trim logs', 'relevanssi' ); ?></label>
</th>
<td>
<input type='number' name='relevanssi_trim_logs' id='relevanssi_trim_logs' value='<?php echo esc_attr( $trim_logs ); ?>' />
<?php esc_html_e( 'How many days of logs to keep in the database.', 'relevanssi' ); ?>
<?php
if ( '0' === $trim_logs ) {
echo '<p class="description">';
esc_html_e( "Big log database table will eventually start to slow down the search, so it's a good idea to use some level of automatic log trimming.", 'relevanssi' );
echo '</p>';
} else {
echo '<p class="description">';
// Translators: %d is the setting for no trim (probably 0).
printf( esc_html__( 'Set to %d for no trimming.', 'relevanssi' ), 0 );
echo '</p>';
}
?>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Export logs', 'relevanssi' ); ?>
</th>
<td>
<?php submit_button( __( 'Export the log as a CSV file', 'relevanssi' ), 'secondary', 'relevanssi_export' ); ?>
<p class="description"><?php esc_html_e( 'Push the button to export the search log as a CSV file.', 'relevanssi' ); ?></p>
</td>
</tr>
</table>
<?php
if ( function_exists( 'relevanssi_click_tracking_interface' ) ) {
relevanssi_click_tracking_interface();
} else {
?>
<h3><?php esc_html_e( 'Click tracking', 'relevanssi' ); ?></h3>
<p><?php esc_html_e( 'Relevanssi Premium has a click tracking feature where you can track which posts are clicked from the search results. That way you can tell what is your most interesting content and how the search is actually used to access posts.', 'relevanssi' ); ?></p>
<?php
}
}

View File

@@ -1,131 +0,0 @@
<?php
/**
* /lib/tabs/overview-tab.php
*
* Prints out the Overview tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the overview tab in Relevanssi settings.
*
* @global array $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_overview_tab() {
global $relevanssi_variables;
$this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
?>
<h2><?php esc_html_e( 'Welcome to Relevanssi!', 'relevanssi' ); ?></h2>
<table class="form-table" role="presentation">
<?php
if ( ! is_plugin_active_for_network( plugin_basename( $relevanssi_variables['file'] ) ) && function_exists( 'relevanssi_form_api_key' ) ) {
relevanssi_form_api_key();
}
if ( function_exists( 'relevanssi_form_hide_post_controls' ) ) {
relevanssi_form_hide_post_controls();
}
if ( function_exists( 'relevanssi_form_do_not_call_home' ) ) {
relevanssi_form_do_not_call_home();
}
if ( function_exists( 'relevanssi_form_update_translations' ) ) {
relevanssi_form_update_translations();
}
?>
<tr>
<th scope="row"><?php esc_html_e( 'Getting started', 'relevanssi' ); ?></th>
<td>
<p><?php esc_html_e( "You've already installed Relevanssi. That's a great first step towards good search experience!", 'relevanssi' ); ?></p>
<ol>
<?php if ( 'done' !== get_option( 'relevanssi_indexed' ) ) : ?>
<?php // Translators: %1$s opens the link, %2$s is the anchor text, %3$s closes the link. ?>
<li><p><?php printf( esc_html__( 'Now, you need an index. Head over to the %1$s%2$s%3$s tab to set up the basic indexing options and to build the index.', 'relevanssi' ), "<a href='" . esc_attr( $this_page ) . "&amp;tab=indexing'>", esc_html__( 'Indexing', 'relevanssi' ), '</a>' ); ?></p>
<p><?php esc_html_e( 'You need to check at least the following options:', 'relevanssi' ); ?><br />
&ndash; <?php esc_html_e( 'Make sure the post types you want to include in the index are indexed.', 'relevanssi' ); ?><br />
<?php // Translators: %s is '_sku'. ?>
&ndash; <?php printf( esc_html__( 'Do you use custom fields to store content you want included? If so, add those too. WooCommerce user? You probably want to include %s.', 'relevanssi' ), '<code>_sku</code>' ); ?></p>
<p><?php esc_html_e( "Then just save the options and build the index. First time you have to do it manually, but after that, it's fully automatic: all changes are reflected in the index without reindexing. (That said, it's a good idea to rebuild the index once a year.)", 'relevanssi' ); ?></p>
</li>
<?php else : ?>
<li><p><?php esc_html_e( 'Great, you already have an index!', 'relevanssi' ); ?></p></li>
<?php endif; ?>
<li>
<?php // Translators: %1$s opens the link, %2$s is the anchor text, %3$s closes the link. ?>
<p><?php printf( esc_html__( 'On the %1$s%2$s%3$s tab, choose whether you want the default operator to be AND (less results, but more precise) or OR (more results, less precise).', 'relevanssi' ), "<a href='" . esc_attr( $this_page ) . "&amp;tab=searching'>", esc_html__( 'Searching', 'relevanssi' ), '</a>' ); ?></p>
</li>
<li>
<?php // Translators: %1$s opens the link, %2$s is the anchor text, %3$s closes the link. ?>
<p><?php printf( esc_html__( 'The next step is the %1$s%2$s%3$s tab, where you can enable the custom excerpts that show the relevant part of post in the search results pages.', 'relevanssi' ), "<a href='" . esc_attr( $this_page ) . "&amp;tab=excerpts'>", esc_html__( 'Excerpts and highlights', 'relevanssi' ), '</a>' ); ?></p>
<p><?php esc_html_e( 'There are couple of options related to that, so if you want highlighting in the results, you can adjust the styles for that to suit the look of your site.', 'relevanssi' ); ?></p>
</li>
<li>
<p><?php esc_html_e( "That's about it! Now you should have Relevanssi up and running. The rest of the options is mostly fine-tuning.", 'relevanssi' ); ?></p>
</li>
</ol>
<p><?php esc_html_e( "Relevanssi doesn't have a separate search widget. Instead, Relevanssi uses the default search widget. Any standard search form will do!", 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Relevanssi Live Ajax Search', 'relevanssi' ); ?></th>
<td>
<?php // Translators: %1$s opens the link, %2$s closes it. ?>
<p><?php printf( esc_html__( 'If you want a live search results, you can use the Relevanssi Live Ajax Search plugin. %1$sYou can find it in the plugin repository%2$s. It will make your search forms show instant results, powered by Relevanssi.', 'relevanssi' ), "<a href='https://wordpress.org/plugins/relevanssi-live-ajax-search/'>", '</a>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Privacy and GDPR compliance', 'relevanssi' ); ?></th>
<td>
<?php // Translators: %1$s and %3$s open the links, %2$s closes them. ?>
<p><?php printf( esc_html__( '%1$sGDPR Compliance at Relevanssi knowledge base%2$s explains how using Relevanssi affects the GDPR compliance and the privacy policies of your site. Relevanssi also supports the %3$sprivacy policy tool%2$s and the WordPress user data export and erase tools.', 'relevanssi' ), "<a href='https://www.relevanssi.com/knowledge-base/gdpr-compliance/'>", '</a>', "<a href='privacy.php'>" ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'For more information', 'relevanssi' ); ?></th>
<td>
<p><?php esc_html_e( "Relevanssi uses the WordPress contextual help. Click 'Help' on the top right corner for more information on many Relevanssi topics.", 'relevanssi' ); ?></p>
<?php // Translators: %1$s opens the link, %2$s closes the link. ?>
<p><?php printf( esc_html__( '%1$sRelevanssi knowledge base%2$s has lots of information about advanced Relevanssi use, including plenty of code samples.', 'relevanssi' ), "<a href='https://www.relevanssi.com/knowledge-base/'>", '</a>' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Do you like Relevanssi?', 'relevanssi' ); ?></th>
<td>
<p><?php esc_html_e( 'If you do, the best way to show your appreciation is to spread the word and perhaps give us a good review on WordPress.org.', 'relevanssi' ); ?></p>
<?php // Translators: %1$s opens the link, %2$s closes the link. ?>
<p><?php printf( esc_html__( 'If you like Relevanssi, leaving a five-star review on WordPress.org will help others discover Relevanssi. %1$sYou can add your review here%2$s.', 'relevanssi' ), "<a href='https://wordpress.org/support/plugin/relevanssi/reviews/#new-post'>", '</a>' ); ?></p>
</td>
</tr>
<?php if ( ! RELEVANSSI_PREMIUM ) { ?>
<tr>
<th scope="row">
<?php esc_html_e( 'Buy Relevanssi Premium', 'relevanssi' ); ?>
</th>
<td>
<p><a href="https://www.relevanssi.com/buy-premium"><?php esc_html_e( 'Buy Relevanssi Premium now', 'relevanssi' ); ?></a>
<?php // Translators: %1$s is the coupon code, %2$s is the year it expires. ?>
<?php printf( esc_html__( 'use coupon code %1$s for 20%% discount (valid at least until the end of %2$s)', 'relevanssi' ), '<strong>FREE2022</strong>', '2022' ); ?></p>
<p><?php esc_html_e( 'Here are some improvements Relevanssi Premium offers:', 'relevanssi' ); ?></p>
<ul class="relevanssi_ul">
<li><?php esc_html_e( 'PDF content indexing', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'A Related posts feature', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Index and search user profile pages', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Index and search taxonomy term pages', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Multisite searches across many subsites', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'WP CLI commands', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Adjust weights separately for each post type and taxonomy', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Internal link anchors can be search terms for the target posts', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Index and search any columns in the wp_posts database', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Hide Relevanssi branding from the User Searches page on a client installation', 'relevanssi' ); ?></li>
<li><?php esc_html_e( 'Redirect search queries to custom URLs', 'relevanssi' ); ?></li>
</ul>
</td>
</tr>
<?php } // End if ( ! RELEVANSSI_PREMIUM ). ?>
</table>
<?php
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* /lib/tabs/redirects-tab.php
*
* Prints out the Redirects tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the redirects tab in Relevanssi settings.
*/
function relevanssi_redirects_tab() {
?>
<h2><?php esc_html_e( 'Redirects', 'relevanssi' ); ?></h2>
<p><?php esc_html_e( 'With Relevanssi Premium, you can set up redirects. These are keywords that automatically redirect the user to certain page, without going through the usual search process. For example, you could set it up so that all searches for "job" automatically lead to your "Careers" page.', 'relevanssi' ); ?></p>
<?php // Translators: %1$s starts the link, %2$s closes it. ?>
<p><?php printf( esc_html__( 'In order to access this and many other delightful Premium features, %1$sbuy Relevanssi Premium here%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/buy-premium/">', '</a>' ); ?></p>
<?php
}

View File

@@ -1,97 +0,0 @@
<?php
/**
* /lib/tabs/search-tab.php
*
* Prints out the search tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the search tab in Relevanssi settings.
*/
function relevanssi_search_tab() {
?>
<p><?php esc_html_e( 'You can use this search to perform Relevanssi searches without any restrictions from WordPress. You can search all post types here.', 'relevanssi' ); ?></p>
<form action="" method="get">
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<label for='s'><?php esc_html_e( 'Search terms', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='s' id='s' size='60' />
</td>
</tr>
<tr>
<th scope="row">
<label for='post_types'><?php esc_html_e( 'Post type', 'relevanssi' ); ?></label>
</th>
<td>
<select name='post_types' id='post_types'>
<option value="any"><?php esc_html_e( 'Any', 'relevanssi' ); ?></option>
<?php
echo implode(
' ',
array_map( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
function ( $post_type ) {
$pt = get_post_type_object( $post_type );
if ( $pt ) {
$post_type_value = esc_attr( $post_type );
$post_type_name = esc_html( $pt->labels->singular_name );
return "<option value='{$post_type_value}'>{$post_type_name}</option>";
}
return null;
},
get_option( 'relevanssi_index_post_types' )
)
);
if ( 'on' === get_option( 'relevanssi_index_users' ) ) {
?>
<option value='user'><?php esc_html_e( 'Users', 'relevanssi' ); ?></option>
<?php
}
?>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for='posts_per_page'><?php esc_html_e( 'Posts per page', 'relevanssi' ); ?></label>
</th>
<td>
<select name='posts_per_page' id='posts_per_page'>
<option value='0'><?php esc_html_e( 'All', 'relevanssi' ); ?></option>
<option>10</option>
<option>50</option>
<option>100</option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for='args'><?php esc_html_e( 'Search parameters', 'relevanssi' ); ?></label>
</th>
<td>
<input type='text' name='args' id='args' size='60' />
<?php // Translators: example query string. ?>
<p class='description'><?php printf( esc_html__( 'Use query parameter formatting here, the same that would appear on search page results URL. For example %s.', 'relevanssi' ), '<code>posts_per_page=10&post_types=page&from=2018-01-01</code>' ); ?></p>
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type='submit' name='search' id='search' value='<?php echo esc_html_x( 'Search', 'button action', 'relevanssi' ); ?>' class='button' />
</td>
</tr>
</table>
</form>
<div id='results'></div>
<?php
}

View File

@@ -1,412 +0,0 @@
<?php
/**
* /lib/tabs/searching-tab.php
*
* Prints out the Searching tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the searching tab in Relevanssi settings.
*
* @global $wpdb The WordPress database interface.
* @global $relevanssi_variables The global Relevanssi variables array.
*/
function relevanssi_searching_tab() {
global $wpdb, $relevanssi_variables;
$implicit = get_option( 'relevanssi_implicit_operator' );
$orderby = get_option( 'relevanssi_default_orderby' );
$fuzzy = get_option( 'relevanssi_fuzzy' );
$content_boost = get_option( 'relevanssi_content_boost' );
$title_boost = get_option( 'relevanssi_title_boost' );
$comment_boost = get_option( 'relevanssi_comment_boost' );
$exact_match_bonus = get_option( 'relevanssi_exact_match_bonus' );
$wpml_only_current = get_option( 'relevanssi_wpml_only_current' );
$polylang_allow_all = get_option( 'relevanssi_polylang_all_languages' );
$admin_search = get_option( 'relevanssi_admin_search' );
$disable_or_fallback = get_option( 'relevanssi_disable_or_fallback' );
$throttle = get_option( 'relevanssi_throttle' );
$respect_exclude = get_option( 'relevanssi_respect_exclude' );
$cat = get_option( 'relevanssi_cat' );
$excat = get_option( 'relevanssi_excat' );
$exclude_posts = get_option( 'relevanssi_exclude_posts' );
$index_post_types = get_option( 'relevanssi_index_post_types' );
$index_users = get_option( 'relevanssi_index_users' );
$index_terms = get_option( 'relevanssi_index_taxonomies' );
$throttle = relevanssi_check( $throttle );
$respect_exclude = relevanssi_check( $respect_exclude );
$admin_search = relevanssi_check( $admin_search );
$wpml_only_current = relevanssi_check( $wpml_only_current );
$polylang_allow_all = relevanssi_check( $polylang_allow_all );
$exact_match_bonus = relevanssi_check( $exact_match_bonus );
$disable_or_fallback = relevanssi_check( $disable_or_fallback );
$implicit_and = relevanssi_select( $implicit, 'AND' );
$implicit_or = relevanssi_select( $implicit, 'OR' );
$orderby_relevance = relevanssi_select( $orderby, 'relevance' );
$orderby_date = relevanssi_select( $orderby, 'post_date' );
$fuzzy_sometimes = relevanssi_select( $fuzzy, 'sometimes' );
$fuzzy_always = relevanssi_select( $fuzzy, 'always' );
$fuzzy_never = relevanssi_select( $fuzzy, 'never' );
$orfallback_visibility = 'screen-reader-text';
if ( 'AND' === $implicit ) {
$orfallback_visibility = '';
}
if ( ! $throttle ) {
$docs_count = get_transient( 'relevanssi_docs_count' );
if ( ! $docs_count ) {
$docs_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT doc) FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc != -1' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
set_transient( 'relevanssi_docs_count', $docs_count, WEEK_IN_SECONDS );
}
} else {
$docs_count = null;
}
?>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<label for='relevanssi_implicit_operator'><?php esc_html_e( 'Default operator', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_implicit_operator' id='relevanssi_implicit_operator'>
<option value='AND' <?php echo esc_html( $implicit_and ); ?>><?php esc_html_e( 'AND - require all terms', 'relevanssi' ); ?></option>
<option value='OR' <?php echo esc_html( $implicit_or ); ?>><?php esc_html_e( 'OR - any term present is enough', 'relevanssi' ); ?></option>
</select>
<p class="description"><?php esc_html_e( 'This setting determines the default operator for the search.', 'relevanssi' ); ?></p>
<?php
if ( RELEVANSSI_PREMIUM ) {
// Translators: %1$s is the name of the 'operator' query variable, %2$s is an example url.
echo "<p class='description'>" . sprintf( esc_html__( 'You can override this setting with the %1$s query parameter, like this: %2$s', 'relevanssi' ), '<code>operator</code>', 'http://www.example.com/?s=term&amp;operator=or' ) . '</p>';
}
?>
</td>
</tr>
<tr id="orfallback" class='<?php echo esc_attr( $orfallback_visibility ); ?>'>
<th scope="row">
<?php esc_html_e( 'Fallback to OR', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Disable the OR fallback.', 'relevanssi' ); ?></legend>
<label for='relevanssi_disable_or_fallback'>
<input type='checkbox' name='relevanssi_disable_or_fallback' id='relevanssi_disable_or_fallback' <?php echo esc_html( $disable_or_fallback ); ?> />
<?php esc_html_e( 'Disable the OR fallback.', 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description"><?php esc_html_e( 'By default, if AND search fails to find any results, Relevanssi will switch the operator to OR and run the search again. You can prevent that by checking this option.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_default_orderby'><?php esc_html_e( 'Default order', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_default_orderby' id='relevanssi_default_orderby'>
<option value='relevance' <?php echo esc_html( $orderby_relevance ); ?>><?php esc_html_e( 'Relevance (highly recommended)', 'relevanssi' ); ?></option>
<option value='post_date' <?php echo esc_html( $orderby_date ); ?>><?php esc_html_e( 'Post date', 'relevanssi' ); ?></option>
</select>
<?php // Translators: name of the query variable. ?>
<p class="description"><?php printf( esc_html__( 'If you want to override this or use multi-layered ordering (eg. first order by relevance, but sort ties by post title), you can use the %s query variable. See Help for more information.', 'relevanssi' ), '<code>orderby</code>' ); ?></p>
<?php if ( RELEVANSSI_PREMIUM ) { ?>
<p class="description"><?php esc_html_e( ' If you want date-based results, see the recent post bonus in the Weights section.', 'relevanssi' ); ?></p>
<?php } // End if ( RELEVANSSI_PREMIUM ). ?>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_fuzzy'><?php esc_html_e( 'Keyword matching', 'relevanssi' ); ?></label>
</th>
<td>
<select name='relevanssi_fuzzy' id='relevanssi_fuzzy'>
<option value='never' <?php echo esc_html( $fuzzy_never ); ?>><?php esc_html_e( 'Whole words', 'relevanssi' ); ?></option>
<option value='always' <?php echo esc_html( $fuzzy_always ); ?>><?php esc_html_e( 'Partial words', 'relevanssi' ); ?></option>
<option value='sometimes' <?php echo esc_html( $fuzzy_sometimes ); ?>><?php esc_html_e( 'Partial words if no hits for whole words', 'relevanssi' ); ?></option>
</select>
<?php if ( $fuzzy_sometimes ) : ?>
<?php // Translators: %1$s is the "partial words if no hits" option and %2$s is the "partial words" option. ?>
<p class="description important"><?php printf( esc_html__( 'Choosing the "%1$s" option may lead to unexpected results. Most of the time the "%2$s" option is the better choice.', 'relevanssi' ), esc_html__( 'Partial words if not hits for whole words', 'relevanssi' ), esc_html__( 'Partial words', 'relevanssi' ) ); ?></p>
<?php endif; ?>
<p class="description"><?php esc_html_e( 'Whole words means Relevanssi only finds posts that include the whole search term.', 'relevanssi' ); ?></p>
<p class="description"><?php esc_html_e( "Partial words also includes cases where the word in the index begins or ends with the search term (searching for 'ana' will match 'anaconda' or 'banana', but not 'banal'). See Help, if you want to make Relevanssi match also inside words.", 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Weights', 'relevanssi' ); ?>
</th>
<td>
<p class="description"><?php esc_html_e( 'All the weights in the table are multipliers. To increase the weight of an element, use a higher number. To make an element less significant, use a number lower than 1.', 'relevanssi' ); ?></p>
<table class="relevanssi-weights-table">
<thead>
<tr>
<th><?php esc_html_e( 'Element', 'relevanssi' ); ?></th>
<th class="col-2"><?php esc_html_e( 'Weight', 'relevanssi' ); ?></th>
</tr>
</thead>
<tr>
<td>
<label for="relevanssi_content_boost"><?php esc_html_e( 'Content', 'relevanssi' ); ?></label>
</td>
<td class="col-2">
<input type='text' name='relevanssi_content_boost' id='relevanssi_content_boost' size='4' value='<?php echo esc_attr( $content_boost ); ?>' />
</td>
</tr>
<tr>
<td>
<label for="relevanssi_title_boost"><?php esc_html_e( 'Titles', 'relevanssi' ); ?></label>
</td>
<td class="col-2">
<input type='text' name='relevanssi_title_boost' id='relevanssi_title_boost' size='4' value='<?php echo esc_attr( $title_boost ); ?>' />
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_link_weight' ) ) {
relevanssi_form_link_weight();
}
?>
<tr>
<td>
<label for="relevanssi_comment_boost"><?php esc_html_e( 'Comment text', 'relevanssi' ); ?></label>
</td>
<td class="col-2">
<input type='text' name='relevanssi_comment_boost' id='relevanssi_comment_boost' size='4' value='<?php echo esc_attr( $comment_boost ); ?>' />
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_post_type_weights' ) ) {
relevanssi_form_post_type_weights();
}
if ( function_exists( 'relevanssi_form_taxonomy_weights' ) ) {
relevanssi_form_taxonomy_weights();
} elseif ( function_exists( 'relevanssi_form_tag_weight' ) ) {
relevanssi_form_tag_weight();
}
if ( function_exists( 'relevanssi_form_recency_weight' ) ) {
relevanssi_form_recency_weight();
}
?>
</table>
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_recency_cutoff' ) ) {
relevanssi_form_recency_cutoff();
}
?>
<tr>
<th scope="row">
<?php esc_html_e( 'Boost exact matches', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Give boost to exact matches.', 'relevanssi' ); ?></legend>
<label for='relevanssi_exact_match_bonus'>
<input type='checkbox' name='relevanssi_exact_match_bonus' id='relevanssi_exact_match_bonus' <?php echo esc_html( $exact_match_bonus ); ?> />
<?php esc_html_e( 'Give boost to exact matches.', 'relevanssi' ); ?>
</label>
</fieldset>
<?php // Translators: %s is the name of the filter hook. ?>
<p class="description"><?php printf( esc_html__( 'If you enable this option, matches where the search query appears in title or content as a phrase will get a weight boost. To adjust the boost, you can use the %s filter hook. See Help for more details.', 'relevanssi' ), '<code>relevanssi_exact_match_bonus</code>' ); ?></p>
</td>
</tr>
<?php
if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_get_post' ) ) {
?>
<tr>
<th scope="row">
<?php esc_html_e( 'WPML', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Limit results to current language.', 'relevanssi' ); ?></legend>
<label for='relevanssi_wpml_only_current'>
<input type='checkbox' name='relevanssi_wpml_only_current' id='relevanssi_wpml_only_current' <?php echo esc_html( $wpml_only_current ); ?> />
<?php esc_html_e( 'Limit results to current language.', 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description"><?php esc_html_e( 'Enabling this option will restrict the results to the currently active language. If the option is disabled, results will include posts in all languages.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php } // WPML. ?>
<?php if ( function_exists( 'pll_get_post' ) ) { ?>
<tr>
<th scope="row">
<?php esc_html_e( 'Polylang', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Allow results from all languages.', 'relevanssi' ); ?></legend>
<label for='relevanssi_polylang_all_languages'>
<input type='checkbox' name='relevanssi_polylang_all_languages' id='relevanssi_polylang_all_languages' <?php echo esc_html( $polylang_allow_all ); ?> />
<?php esc_html_e( 'Allow results from all languages.', 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description"><?php esc_html_e( 'By default Polylang restricts the search to the current language. Enabling this option will lift this restriction.', 'relevanssi' ); ?></p>
</td>
</tr>
<?php } // Polylang. ?>
<tr>
<th scope="row">
<?php esc_html_e( 'Admin search', 'relevanssi' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Use Relevanssi for admin searches.', 'relevanssi' ); ?></legend>
<label for='relevanssi_admin_search'>
<input type='checkbox' name='relevanssi_admin_search' id='relevanssi_admin_search' <?php echo esc_html( $admin_search ); ?> />
<?php esc_html_e( 'Use Relevanssi for admin searches.', 'relevanssi' ); ?>
</label>
</fieldset>
<p class="description"><?php esc_html_e( "If checked, Relevanssi will be used for searches in the admin interface. The page search doesn't use Relevanssi, because WordPress works like that.", 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php // Translators: %s is 'exclude_from_search'. ?>
<?php printf( esc_html__( 'Respect %s', 'relevanssi' ), 'exclude_from_search' ); ?>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Respect exclude_from_search for custom post types', 'relevanssi' ); ?></legend>
<label for='relevanssi_respect_exclude'>
<input type='checkbox' name='relevanssi_respect_exclude' id='relevanssi_respect_exclude' <?php echo esc_html( $respect_exclude ); ?> />
<?php // Translators: %s is 'exclude_from_search'. ?>
<?php printf( esc_html__( 'Respect %s for custom post types', 'relevanssi' ), '<code>exclude_from_search</code>' ); ?>
</label>
<p class="description"><?php esc_html_e( "If checked, Relevanssi won't display posts of custom post types that have 'exclude_from_search' set to true.", 'relevanssi' ); ?></p>
<?php
if ( ! empty( $respect_exclude ) ) {
$pt_1 = get_post_types( array( 'exclude_from_search' => '1' ) );
$pt_2 = get_post_types( array( 'exclude_from_search' => true ) );
$private_types = array_merge( $pt_1, $pt_2 );
$problem_post_types = array_intersect( $index_post_types, $private_types );
if ( ! empty( $problem_post_types ) ) {
?>
<p class="description important">
<?php
esc_html_e( "You probably should uncheck this option, because you've set Relevanssi to index the following non-public post types:", 'relevanssi' );
echo ' ' . esc_html( implode( ', ', $problem_post_types ) );
?>
</p>
<?php
}
}
?>
</fieldset>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Throttle searches', 'relevanssi' ); ?>
</th>
<td id="throttlesearches">
<div id="throttle_enabled">
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Throttle searches.', 'relevanssi' ); ?></legend>
<label for='relevanssi_throttle'>
<input type='checkbox' name='relevanssi_throttle' id='relevanssi_throttle' <?php echo esc_html( $throttle ); ?> />
<?php esc_html_e( 'Throttle searches.', 'relevanssi' ); ?>
</label>
</fieldset>
<?php if ( $docs_count && $docs_count < 1000 ) { ?>
<p class="description important"><?php esc_html_e( "Your database is so small that you don't need to enable this.", 'relevanssi' ); ?></p>
<?php } ?>
<p class="description"><?php esc_html_e( 'If this option is checked, Relevanssi will limit search results to at most 500 results per term. This will improve performance, but may cause some relevant documents to go unfound. See Help for more details.', 'relevanssi' ); ?></p>
<?php if ( 'post_date' === $orderby && ( 'on' === $index_users || 'on' === $index_terms ) ) { ?>
<p class="important"><?php esc_html_e( 'You have the default ordering set to post date and have enabled user or taxonomy term indexing. If you enable the throttle, the search results will only include posts. Users and taxonomy terms will be excluded. Either keep the throttle disabled or set the post ordering to relevance.', 'relevanssi' ); ?></p>
<?php } ?>
</div>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Category restriction', 'relevanssi' ); ?>
</th>
<td>
<div class="categorydiv" style="max-width: 400px">
<div class="tabs-panel">
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Category restriction', 'relevanssi' ); ?></legend>
<ul id="category_inclusion_checklist">
<?php
$selected_cats = explode( ',', $cat );
$walker = get_relevanssi_taxonomy_walker();
$walker->name = 'relevanssi_cat';
wp_terms_checklist(
0,
array(
'taxonomy' => 'category',
'selected_cats' => $selected_cats,
'walker' => $walker,
)
);
?>
</ul>
</fieldset>
<input type="hidden" name="relevanssi_cat_active" value="1" />
</div>
</div>
<p class="description"><?php esc_html_e( 'You can restrict search results to a category for all searches. For restricting on a per-search basis and more options (eg. tag restrictions), see Help.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Category exclusion', 'relevanssi' ); ?>
</th>
<td>
<div class="categorydiv" style="max-width: 400px">
<div class="tabs-panel">
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Category exclusion', 'relevanssi' ); ?></legend>
<ul id="category_exclusion_checklist">
<?php
$selected_cats = explode( ',', $excat );
$walker = get_relevanssi_taxonomy_walker();
$walker->name = 'relevanssi_excat';
wp_terms_checklist(
0,
array(
'taxonomy' => 'category',
'selected_cats' => $selected_cats,
'walker' => $walker,
)
);
?>
</ul>
<input type="hidden" name="relevanssi_excat_active" value="1" />
</fieldset>
</div>
</div>
<p class="description"><?php esc_html_e( 'Posts in these categories are not included in search results. To exclude the posts completely from the index, see Help.', 'relevanssi' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for='relevanssi_exclude_posts'><?php esc_html_e( 'Post exclusion', 'relevanssi' ); ?>
</th>
<td>
<input type='text' name='relevanssi_exclude_posts' id='relevanssi_exclude_posts' size='60' value='<?php echo esc_attr( $exclude_posts ); ?>' />
<p class="description"><?php esc_html_e( "Enter a comma-separated list of post or page ID's to exclude those pages from the search results.", 'relevanssi' ); ?></p>
<?php if ( RELEVANSSI_PREMIUM ) { ?>
<p class="description"><?php esc_html_e( "With Relevanssi Premium, it's better to use the check box on post edit pages. That will remove the posts completely from the index, and will work with multisite searches unlike this setting.", 'relevanssi' ); ?></p>
<?php } ?>
</td>
</tr>
<?php
if ( function_exists( 'relevanssi_form_searchblogs_setting' ) ) {
relevanssi_form_searchblogs_setting();
}
?>
</table>
<?php
}

View File

@@ -1,149 +0,0 @@
<?php
/**
* /lib/tabs/stopwords-tab.php
*
* Prints out the Stopwords tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the stopwords tab in Relevanssi settings.
*/
function relevanssi_stopwords_tab() {
if ( class_exists( 'Polylang', false ) && ! relevanssi_get_current_language() ) {
relevanssi_polylang_all_languages_stopwords();
return;
}
?>
<h3 id="stopwords"><?php esc_html_e( 'Stopwords', 'relevanssi' ); ?></h3>
<?php
relevanssi_show_stopwords();
?>
<h3 id="bodystopwords"><?php esc_html_e( 'Content stopwords', 'relevanssi' ); ?></h3>
<?php
if ( function_exists( 'relevanssi_show_body_stopwords' ) ) {
relevanssi_show_body_stopwords();
} else {
printf(
'<p>%s</p>',
esc_html__(
'Content stopwords are a premium feature where you can set stopwords that only apply to the post content. Those stopwords will still be indexed if they appear in post titles, tags, categories, custom fields or other parts of the post. To use content stopwords, you need Relevanssi Premium.',
'relevanssi'
)
);
}
/**
* Filters whether the common words list is displayed or not.
*
* The list of 25 most common words is displayed by default, but if the
* index is big, displaying the list can take a long time. This filter can
* be used to turn the list off.
*
* @param boolean If true, show the list; if false, don't show it.
*/
if ( apply_filters( 'relevanssi_display_common_words', true ) ) {
relevanssi_common_words( 25 );
}
}
/**
* Displays a list of stopwords.
*
* Displays the list of stopwords and gives the controls for adding new
* stopwords.
*/
function relevanssi_show_stopwords() {
printf(
'<p>%s</p>',
esc_html__(
'Enter a word here to add it to the list of stopwords. The word will automatically be removed from the index, so re-indexing is not necessary. You can enter many words at the same time, separate words with commas.',
'relevanssi'
)
);
?>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<label for="addstopword"><p><?php esc_html_e( 'Stopword(s) to add', 'relevanssi' ); ?>
</th>
<td>
<textarea name="addstopword" id="addstopword" rows="2" cols="80"></textarea>
<p><input type="submit" value="<?php esc_attr_e( 'Add', 'relevanssi' ); ?>" class='button' /></p>
</td>
</tr>
</table>
<p><?php esc_html_e( "Here's a list of stopwords in the database. Click a word to remove it from stopwords. Removing stopwords won't automatically return them to index, so you need to re-index all posts after removing stopwords to get those words back to index.", 'relevanssi' ); ?></p>
<table class="form-table" role="presentation">
<tr>
<th scope="row">
<?php esc_html_e( 'Current stopwords', 'relevanssi' ); ?>
</th>
<td>
<ul>
<?php
$stopwords = array_map( 'stripslashes', relevanssi_fetch_stopwords() );
sort( $stopwords );
$exportlist = htmlspecialchars( implode( ', ', $stopwords ) );
array_walk(
$stopwords,
function ( $term ) {
printf( '<li style="display: inline;"><input type="submit" name="removestopword" value="%s"/></li>', esc_attr( $term ) );
}
);
?>
</ul>
<p>
<input
type="submit"
id="removeallstopwords"
name="removeallstopwords"
value="<?php esc_attr_e( 'Remove all stopwords', 'relevanssi' ); ?>"
class='button'
/>
<input
type="submit"
id="repopulatestopwords"
name="repopulatestopwords"
value="<?php esc_attr_e( 'Add default stopwords', 'relevanssi' ); ?>"
class='button'
/>
</p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Exportable list of stopwords', 'relevanssi' ); ?>
</th>
<td>
<label for="stopwords" class="screen-reader-text"><?php esc_html_e( 'Exportable list of stopwords', 'relevanssi' ); ?></label>
<textarea name="stopwords" id="stopwords" rows="2" cols="80"><?php echo esc_textarea( $exportlist ); ?></textarea>
<p class="description"><?php esc_html_e( 'You can copy the list of stopwords here if you want to back up the list, copy it to a different blog or otherwise need the list.', 'relevanssi' ); ?></p>
</td>
</tr>
</table>
<?php
}
/**
* Displays an error message when Polylang is in all languages mode.
*/
function relevanssi_polylang_all_languages_stopwords() {
?>
<h3 id="stopwords"><?php esc_html_e( 'Stopwords', 'relevanssi' ); ?></h3>
<p class="description"><?php esc_html_e( 'You are using Polylang and are in "Show all languages" mode. Please select a language before adjusting the stopword settings.', 'relevanssi' ); ?></p>
<?php
}

View File

@@ -1,102 +0,0 @@
<?php
/**
* /lib/tabs/synonyms-tab.php
*
* Prints out the Synonyms tab in Relevanssi settings.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the synonyms tab in Relevanssi settings.
*/
function relevanssi_synonyms_tab() {
$current_language = relevanssi_get_current_language();
if ( class_exists( 'Polylang', false ) && ! $current_language ) {
relevanssi_polylang_all_languages_synonyms();
return;
}
$synonyms_array = get_option( 'relevanssi_synonyms', array() );
$synonyms = isset( $synonyms_array[ $current_language ] ) ? $synonyms_array[ $current_language ] : '';
if ( isset( $synonyms ) ) {
$synonyms = str_replace( ';', "\n", $synonyms );
} else {
$synonyms = '';
}
$synonyms_disabled = false;
$operator = get_option( 'relevanssi_implicit_operator' );
if ( 'AND' === $operator ) {
$index_synonyms = get_option( 'relevanssi_index_synonyms', false );
if ( 'on' !== $index_synonyms ) {
$synonyms_disabled = true;
}
}
?>
<h3 id="synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></h3>
<table class="form-table" role="presentation">
<tr
<?php
if ( $synonyms_disabled ) {
echo "class='relevanssi_disabled'";
}
?>
>
<?php if ( $synonyms_disabled ) : ?>
<tr>
<th scope="row">
<p class="important"><?php esc_html_e( 'No synonyms!', 'relevanssi' ); ?></p>
</th>
<td>
<p class="important"><?php esc_html_e( 'Synonyms are disabled because the searching operator is set to AND. Enable OR searching to use the synonyms.', 'relevanssi' ); ?></p>
<?php if ( RELEVANSSI_PREMIUM ) : ?>
<p class="description"><?php esc_html_e( "If you want to use synonyms in AND searches, enable synonym indexing on the Indexing tab. Also, any changes to the synonyms won't take effect until you rebuild the index.", 'relevanssi' ); ?></p>
<?php else : ?>
<p class="description"><?php esc_html_e( 'Relevanssi Premium has a feature that allows you to include the synonyms in the indexing. This makes it possible to use synonyms in AND searches.', 'relevanssi' ); ?></p>
<?php endif; ?>
</td>
</tr>
<?php endif; ?>
<th scope="row">
<label for="relevanssi_synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></label>
</th>
<td>
<p class="description"><?php esc_html_e( 'Add synonyms here to make the searches find better results. If you notice your users frequently misspelling a product name, or for other reasons use many names for one thing, adding synonyms will make the results better.', 'relevanssi' ); ?></p>
<p class="description"><?php esc_html_e( "Do not go overboard, though, as too many synonyms can make the search confusing: users understand if a search query doesn't match everything, but they get confused if the searches match to unexpected things.", 'relevanssi' ); ?></p>
<br />
<textarea name='relevanssi_synonyms' id='relevanssi_synonyms' rows='9' cols='60'
<?php
if ( $synonyms_disabled ) {
echo 'disabled';
}
?>
><?php echo esc_textarea( $synonyms ); ?></textarea>
<p class="description"><?php _e( 'The format here is <code>key = value</code>. If you add <code>dog = hound</code> to the list of synonyms, searches for <code>dog</code> automatically become a search for <code>dog hound</code> and will thus match to posts that include either <code>dog</code> or <code>hound</code>. This only works in OR searches: in AND searches the synonyms only restrict the search, as now the search only finds posts that contain <strong>both</strong> <code>dog</code> and <code>hound</code>.', 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
<p class="description"><?php _e( 'The synonyms are one direction only. If you want both directions, add the synonym again, reversed: <code>hound = dog</code>.', 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
<p class="description"><?php _e( "It's possible to use phrases for the value, but not for the key. <code>dog = \"great dane\"</code> works, but <code>\"great dane\" = dog</code> doesn't.", 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
</td>
</tr>
</table>
<?php
}
/**
* Displays an error message when Polylang is in all languages mode.
*/
function relevanssi_polylang_all_languages_synonyms() {
?>
<h3 id="synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></h3>
<p class="description"><?php esc_html_e( 'You are using Polylang and are in "Show all languages" mode. Please select a language before adjusting the synonym settings.', 'relevanssi' ); ?></p>
<?php
}

View File

@@ -1,154 +0,0 @@
<?php
/**
* /lib/uninstall.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Drops the database tables.
*
* Drops the Relevanssi database tables
*
* @global $wpdb The WordPress database interface.
*/
function relevanssi_drop_database_tables() {
global $wpdb;
if ( defined( 'RELEVANSSI_PREMIUM' ) && RELEVANSSI_PREMIUM && ! defined( 'UNINSTALLING_RELEVANSSI_PREMIUM' ) ) {
// Relevanssi Premium exists, do not drop the tables.
return;
}
$relevanssi_table = $wpdb->prefix . 'relevanssi';
$stopword_table = $wpdb->prefix . 'relevanssi_stopwords';
$log_table = $wpdb->prefix . 'relevanssi_log';
$tracking_table = $wpdb->prefix . 'relevanssi_tracking';
// phpcs:disable WordPress.DB.PreparedSQL
if ( $wpdb->get_var( "SHOW TABLES LIKE '$stopword_table'" ) === $stopword_table ) {
$wpdb->query( "DROP TABLE $stopword_table" );
}
if ( $wpdb->get_var( "SHOW TABLES LIKE '$relevanssi_table'" ) === $relevanssi_table ) {
$wpdb->query( "DROP TABLE $relevanssi_table" );
}
if ( $wpdb->get_var( "SHOW TABLES LIKE '$log_table'" ) === $log_table ) {
$wpdb->query( "DROP TABLE $log_table" );
}
if ( $wpdb->get_var( "SHOW TABLES LIKE '$tracking_table'" ) === $tracking_table ) {
$wpdb->query( "DROP TABLE $tracking_table" );
}
// phpcs:enable WordPress.DB.PreparedSQL
}
/**
* Uninstalls Relevanssi.
*
* Deletes all options and removes database tables.
*
* @global object $wpdb The WordPress database interface.
*/
function relevanssi_uninstall_free() {
if ( defined( 'RELEVANSSI_PREMIUM' ) && RELEVANSSI_PREMIUM && ! defined( 'UNINSTALLING_RELEVANSSI_PREMIUM' ) ) {
// Relevanssi Premium exists, do not drop the tables.
return;
}
delete_option( 'relevanssi_admin_search' );
delete_option( 'relevanssi_bg_col' );
delete_option( 'relevanssi_cat' );
delete_option( 'relevanssi_class' );
delete_option( 'relevanssi_comment_boost' );
delete_option( 'relevanssi_content_boost' );
delete_option( 'relevanssi_css' );
delete_option( 'relevanssi_db_version' );
delete_option( 'relevanssi_debugging_mode' );
delete_option( 'relevanssi_default_orderby' );
delete_option( 'relevanssi_disable_or_fallback' );
delete_option( 'relevanssi_disable_shortcodes' );
delete_option( 'relevanssi_doc_count' );
delete_option( 'relevanssi_exact_match_bonus' );
delete_option( 'relevanssi_excat' );
delete_option( 'relevanssi_excerpt_allowable_tags' );
delete_option( 'relevanssi_excerpt_custom_fields' );
delete_option( 'relevanssi_excerpt_length' );
delete_option( 'relevanssi_excerpt_type' );
delete_option( 'relevanssi_excerpts' );
delete_option( 'relevanssi_exclude_posts' );
delete_option( 'relevanssi_expand_highlights' );
delete_option( 'relevanssi_expand_shortcodes' );
delete_option( 'relevanssi_extag' );
delete_option( 'relevanssi_fuzzy' );
delete_option( 'relevanssi_hide_branding' );
delete_option( 'relevanssi_highlight' );
delete_option( 'relevanssi_highlight_comments' );
delete_option( 'relevanssi_highlight_docs' );
delete_option( 'relevanssi_hilite_title' );
delete_option( 'relevanssi_implicit_operator' );
delete_option( 'relevanssi_index' );
delete_option( 'relevanssi_index_author' );
delete_option( 'relevanssi_index_comments' );
delete_option( 'relevanssi_index_excerpt' );
delete_option( 'relevanssi_index_fields' );
delete_option( 'relevanssi_index_image_files' );
delete_option( 'relevanssi_index_post_types' );
delete_option( 'relevanssi_index_taxonomies' );
delete_option( 'relevanssi_index_taxonomies_list' );
delete_option( 'relevanssi_index_terms' );
delete_option( 'relevanssi_indexed' );
delete_option( 'relevanssi_link_boost' );
delete_option( 'relevanssi_log_queries' );
delete_option( 'relevanssi_log_queries_with_ip' );
delete_option( 'relevanssi_min_word_length' );
delete_option( 'relevanssi_omit_from_logs' );
delete_option( 'relevanssi_polylang_all_languages' );
delete_option( 'relevanssi_post_type_weights' );
delete_option( 'relevanssi_punctuation' );
delete_option( 'relevanssi_respect_exclude' );
delete_option( 'relevanssi_seo_noindex' );
delete_option( 'relevanssi_show_matches' );
delete_option( 'relevanssi_show_matches_text' );
delete_option( 'relevanssi_show_post_controls' );
delete_option( 'relevanssi_stopwords' );
delete_option( 'relevanssi_synonyms' );
delete_option( 'relevanssi_terms_count' );
delete_option( 'relevanssi_thousand_separator' );
delete_option( 'relevanssi_throttle' );
delete_option( 'relevanssi_throttle_limit' );
delete_option( 'relevanssi_title_boost' );
delete_option( 'relevanssi_trim_logs' );
delete_option( 'relevanssi_txt_col' );
delete_option( 'relevanssi_wpml_only_current' );
// Unused options, removed in case they are still left.
delete_option( 'relevanssi_cache_seconds' );
delete_option( 'relevanssi_custom_types' );
delete_option( 'relevanssi_enable_cache' );
delete_option( 'relevanssi_hidesponsor' );
delete_option( 'relevanssi_index_attachments' );
delete_option( 'relevanssi_index_drafts' );
delete_option( 'relevanssi_index_limit' );
delete_option( 'relevanssi_index_type' );
delete_option( 'relevanssi_show_matches_txt' );
delete_option( 'relevanssi_tag_boost' );
delete_option( 'relevanssi_include_cats' );
delete_option( 'relevanssi_include_tags' );
delete_option( 'relevanssi_custom_taxonomies' );
delete_option( 'relevanssi_taxonomies_to_index' );
delete_option( 'relevanssi_highlight_docs_external' );
delete_option( 'relevanssi_word_boundaries' );
delete_option( 'relevanssi_expst' );
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_relevanssi_noindex_reason'" );
wp_clear_scheduled_hook( 'relevanssi_update_counts' );
relevanssi_drop_database_tables();
}

View File

@@ -1,385 +0,0 @@
<?php
/**
* /lib/user-searches.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
/**
* Prints out the 'User searches' page.
*/
function relevanssi_search_stats() {
$relevanssi_hide_branding = get_option( 'relevanssi_hide_branding' );
if ( 'on' === $relevanssi_hide_branding ) {
$options_txt = __( 'User searches', 'relevanssi' );
} else {
$options_txt = __( 'Relevanssi User Searches', 'relevanssi' );
}
if ( isset( $_REQUEST['relevanssi_reset'] ) && current_user_can( 'manage_options' ) ) {
check_admin_referer( 'relevanssi_reset_logs', '_relresnonce' );
if ( isset( $_REQUEST['relevanssi_reset_code'] ) ) {
if ( 'reset' === $_REQUEST['relevanssi_reset_code'] ) {
$verbose = true;
relevanssi_truncate_logs( $verbose );
}
}
}
printf( "<div class='wrap'><h2>%s</h2>", esc_html( $options_txt ) );
$premium_screens_displayed =
function_exists( 'relevanssi_handle_insights_screens' )
? relevanssi_handle_insights_screens( $_REQUEST )
: false;
if ( ! $premium_screens_displayed ) {
if ( 'on' === get_option( 'relevanssi_log_queries' ) ) {
relevanssi_query_log();
} else {
printf( '<p>%s</p>', esc_html__( 'Enable query logging to see stats here.', 'relevanssi' ) );
}
}
}
/**
* Shows the query log with the most common queries
*
* Uses relevanssi_total_queries() and relevanssi_date_queries() to fetch the data.
*/
function relevanssi_query_log() {
global $wpdb, $relevanssi_variables;
$data = $wpdb->get_results(
'SELECT LEFT( `time`, 10 ) as `day`, count(*) as `count` ' .
"FROM {$relevanssi_variables['log_table']} " . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
'GROUP BY LEFT( `time`, 10 )'
);
$labels = array();
$values = array();
$from = gmdate( 'Y-m-d' );
foreach ( $data as $point ) {
if ( $point->day < $from ) {
$from = $point->day;
}
}
wp_verify_nonce( '_relevanssi_nonce', 'relevanssi_user_searches' );
$from_and_to = relevanssi_from_and_to( $_REQUEST, $from );
$to = $from_and_to['to'];
$from = $from_and_to['from'];
foreach ( $data as $point ) {
if ( $point->day >= $from && $point->day <= $to ) {
$labels[] = gmdate( 'M j', strtotime( $point->day ) );
$values[] = $point->count;
}
}
?>
<form method="post" style="background: white; padding: 10px; margin-top: 20px;">
<?php
wp_nonce_field( 'relevanssi_user_searches', '_relevanssi_nonce', true, true );
?>
<div style="display: grid; grid-template-columns: 1fr 1fr; grid-gap: 20px">
<div>
<?php echo esc_html__( 'From:', 'relevanssi' ); ?> <input type="date" name="from" value="<?php echo esc_attr( $from ); ?>" />
<?php echo esc_html__( 'To:', 'relevanssi' ); ?> <input type="date" name="to" value="<?php echo esc_attr( $to ); ?>" />
<input type="submit" value="<?php echo esc_attr( __( 'Filter', 'relevanssi' ) ); ?>" /></p>
</div>
<div>
<input type="submit" value="<?php echo esc_attr( __( 'Year so far', 'relevanssi' ) ); ?>" name="this_year" style="margin-bottom: 10px" />
<input type="submit" value="<?php echo esc_attr( __( 'This month', 'relevanssi' ) ); ?>" name="this_month" />
<input type="submit" value="<?php echo esc_attr( __( 'Last month', 'relevanssi' ) ); ?>" name="last_month" />
<input type="submit" value="<?php echo esc_attr( __( '30 days', 'relevanssi' ) ); ?>" name="last_30" />
<input type="submit" value="<?php echo esc_attr( __( 'This week', 'relevanssi' ) ); ?>" name="this_week" />
<input type="submit" value="<?php echo esc_attr( __( 'Last week', 'relevanssi' ) ); ?>" name="last_week" />
<input type="submit" value="<?php echo esc_attr( __( '7 days', 'relevanssi' ) ); ?>" name="last_7" />
<input type="submit" value="<?php echo esc_attr( __( 'All history', 'relevanssi' ) ); ?>" name="everything" />
</div>
</div>
</form>
<?php
relevanssi_create_line_chart(
$labels,
array(
__( '# of Searches', 'relevanssi' ) => $values,
)
);
$total_queries = relevanssi_total_queries( $from, $to );
?>
<div style="background: white; padding: 10px; display: grid; grid-template-columns: 1fr 2fr 2fr; grid-gap: 20px; margin-top: 20px">
<div>
<div style="margin-bottom: 20px"><?php esc_html_e( 'Total searches', 'relevanssi' ); ?>
<span style="display: block; font-size: 42px; font-weight: bolder; line-height: 50px">
<?php echo intval( $total_queries ); ?>
</span>
</div>
<div style="margin-bottom: 20px"><?php esc_html_e( 'Searches that found nothing', 'relevanssi' ); ?>
<span style="display: block; font-size: 42px; font-weight: bolder; line-height: 50px">
<?php echo intval( relevanssi_nothing_found_queries( $from, $to ) ); ?>
</span>
</div>
<?php
if ( function_exists( 'relevanssi_user_searches_clicks' ) ) {
relevanssi_user_searches_clicks( $from, $to, $total_queries );
}
?>
</div>
<div>
<h3><?php esc_html_e( 'Successful searches', 'relevanssi' ); ?></h3>
<p><?php esc_html_e( '"Hits" is the average hits this search query has found.', 'relevanssi' ); ?></p>
<?php
if ( ! function_exists( 'relevanssi_get_query_clicks' ) ) {
?>
<p><?php esc_html_e( 'In order to see the clicks, you need Relevanssi Premium.', 'relevanssi' ); ?></p>
<?php
} elseif ( 'on' !== get_option( 'relevanssi_click_tracking' ) ) {
?>
<p><?php esc_html_e( 'In order to see the clicks, you need to enable click tracking. Click tracking is not currently enabled, and you\'re not collecting new clicks.', 'relevanssi' ); ?></p>
<?php
}
relevanssi_date_queries( $from, $to, 'good' );
?>
</div>
<div>
<h3><?php esc_html_e( 'Unsuccessful searches', 'relevanssi' ); ?></h3>
<p><?php esc_html_e( 'These queries have found no results.', 'relevanssi' ); ?></p>
<?php relevanssi_date_queries( $from, $to, 'bad' ); ?>
</div>
</div>
<?php
if ( current_user_can( 'manage_options' ) ) {
echo '<div style="clear: both"></div>';
printf( '<h3>%s</h3>', esc_html__( 'Reset Logs', 'relevanssi' ) );
print( "<form method='post'>" );
wp_nonce_field( 'relevanssi_reset_logs', '_relresnonce', true, true );
// Translators: do not translate "reset".
$message = esc_html__(
'To reset the logs, type "reset" into the box here and click the Reset button',
'relevanssi'
);
if ( RELEVANSSI_PREMIUM ) {
// Translators: do not translate "reset".
$message = esc_html__(
'To reset the logs, type "reset" into the box here and click the Reset button. This will reset both the search log and the click tracking log.',
'relevanssi'
);
}
printf(
'<p><label for="relevanssi_reset_code">%s</label>
<input type="text" id="relevanssi_reset_code" name="relevanssi_reset_code" />
<input type="submit" name="relevanssi_reset" value="%s" class="button" /></p></form>',
$message, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped.
esc_html__( 'Reset', 'relevanssi' )
);
}
echo '</div>';
}
/**
* Shows the total number of searches on 'User searches' page.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param string $from The start date.
* @param string $to The end date.
*
* @return int The number of searches.
*/
function relevanssi_total_queries( string $from, string $to ) {
global $wpdb, $relevanssi_variables;
$log_table = $relevanssi_variables['log_table'];
$count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(id) FROM $log_table " // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
. 'WHERE time >= %s
AND time <= %s',
$from . ' 00:00:00',
$to . ' 23:59:59'
)
);
return $count;
}
/**
* Shows the total number of searches on 'User searches' page.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param string $from The start date.
* @param string $to The end date.
*/
function relevanssi_nothing_found_queries( string $from, string $to ) {
global $wpdb, $relevanssi_variables;
$log_table = $relevanssi_variables['log_table'];
$count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(id) FROM $log_table " // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
. 'WHERE time >= %s
AND time <= %s
AND hits = 0',
$from . ' 00:00:00',
$to . ' 23:59:59'
)
);
return $count;
}
/**
* Shows the most common search queries on different time periods.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables array.
*
* @param string $from The beginning date.
* @param string $to The ending date.
* @param string $version If 'good', show the searches that found something; if
* 'bad', show the searches that didn't find anything. Default 'good'.
*/
function relevanssi_date_queries( string $from, string $to, string $version = 'good' ) {
global $wpdb, $relevanssi_variables;
$log_table = $relevanssi_variables['log_table'];
/**
* Filters the number of most common queries to show.
*
* @param int The number of most common queries to show, default 100.
*/
$limit = apply_filters( 'relevanssi_user_searches_limit', 100 );
if ( 'good' === $version ) {
$queries = $wpdb->get_results(
$wpdb->prepare(
'SELECT COUNT(DISTINCT(id)) as cnt, query, AVG(hits) AS hits ' .
"FROM $log_table " . // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
'WHERE time >= %s
AND time <= %s
AND hits > 0
GROUP BY query
ORDER BY cnt DESC
LIMIT %d',
$from . ' 00:00:00',
$to . ' 23:59:59',
$limit
)
);
}
if ( 'bad' === $version ) {
$queries = $wpdb->get_results(
$wpdb->prepare(
'SELECT COUNT(DISTINCT(id)) as cnt, query, hits ' .
"FROM $log_table " . // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
'WHERE time >= %s
AND time <= %s
AND hits = 0
GROUP BY query
ORDER BY cnt DESC
LIMIT %d',
$from . ' 00:00:00',
$to . ' 23:59:59',
$limit
)
);
}
if ( count( $queries ) > 0 ) {
if ( 'good' === $version ) {
printf(
"<table class='widefat' style='border: none'>
<thead>
<tr>
<th>%s</th>
<th style='text-align: center'>#</th>
<th style='text-align: center'>%s</th>
<th style='text-align: center'>%s</th>
</tr>
</thead>
<tbody>",
esc_html__( 'Query', 'relevanssi' ),
esc_html__( 'Hits', 'relevanssi' ),
esc_html__( 'Clicks', 'relevanssi' )
);
} else {
printf(
"<table class='widefat' style='border: none'>
<thead>
<tr>
<th>%s</th>
<th style='text-align: center'>#</th>
</tr>
</thead>
<tbody>",
esc_html__( 'Query', 'relevanssi' )
);
}
$url = get_bloginfo( 'url' );
foreach ( $queries as $query ) {
if ( 'good' === $version && function_exists( 'relevanssi_get_query_clicks' ) ) {
$clicks = intval( relevanssi_get_query_clicks( $query->query ) );
} else {
$clicks = '-';
}
$search_parameter = rawurlencode( $query->query );
/**
* Filters the query URL for the user searches page.
*
* @param string Query URL.
*/
$query_url = apply_filters( 'relevanssi_user_searches_query_url', $url . '/?s=' . $search_parameter );
if ( function_exists( 'relevanssi_insights_link' ) ) {
$query_link = relevanssi_insights_link( $query );
} else {
$query_link = wp_kses( relevanssi_hyphenate( $query->query ), 'strip' );
}
if ( 'good' === $version ) {
printf(
"<tr>
<td>%s <a href='%s'><span class='dashicons dashicons-external'></span></a></td>
<td style='padding: 3px 5px; text-align: center'>%d</td>
<td style='padding: 3px 5px; text-align: center'>%d</td>
<td style='padding: 3px 5px; text-align: center'>%s</td>
</tr>",
$query_link, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
esc_attr( $query_url ),
intval( $query->cnt ),
intval( $query->hits ),
$clicks // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
);
} else {
printf(
"<tr>
<td>%s <a href='%s'><span class='dashicons dashicons-external'></span></a></td>
<td style='padding: 3px 5px; text-align: center'>%d</td>
</tr>",
$query_link, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
esc_attr( $query_url ),
intval( $query->cnt )
);
}
}
echo '</tbody></table>';
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,742 +0,0 @@
<?php
/**
* /premium/admin-ajax.php
*
* @package Relevanssi_Premium
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_action( 'wp_ajax_relevanssi_list_pdfs', 'relevanssi_list_pdfs_action' );
add_action( 'wp_ajax_relevanssi_wipe_pdfs', 'relevanssi_wipe_pdfs_action' );
add_action( 'wp_ajax_relevanssi_index_pdfs', 'relevanssi_index_pdfs_action' );
add_action( 'wp_ajax_relevanssi_send_pdf', 'relevanssi_send_pdf' );
add_action( 'wp_ajax_relevanssi_send_url', 'relevanssi_send_url' );
add_action( 'wp_ajax_relevanssi_get_pdf_errors', 'relevanssi_get_pdf_errors_action' );
add_action( 'wp_ajax_relevanssi_index_taxonomies', 'relevanssi_index_taxonomies_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_count_taxonomies', 'relevanssi_count_taxonomies_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_index_post_type_archives', 'relevanssi_index_post_type_archives_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_index_users', 'relevanssi_index_users_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_count_users', 'relevanssi_count_users_ajax_wrapper' );
add_action( 'wp_ajax_relevanssi_list_taxonomies', 'relevanssi_list_taxonomies_wrapper' );
add_action( 'wp_ajax_relevanssi_related_posts', 'relevanssi_get_related_posts' );
add_action( 'wp_ajax_relevanssi_related_remove', 'relevanssi_add_to_exclude_list' );
add_action( 'wp_ajax_relevanssi_related_return', 'relevanssi_remove_from_exclude_list' );
add_action( 'wp_ajax_relevanssi_pin_post', 'relevanssi_pin_post' );
add_action( 'wp_ajax_relevanssi_unpin_post', 'relevanssi_unpin_post' );
add_action( 'wp_ajax_relevanssi_get_words', 'relevanssi_ajax_get_words' );
add_action( 'wp_ajax_nopriv_relevanssi_get_words', 'relevanssi_ajax_get_words' );
add_action( 'wp_ajax_relevanssi_index_pdf', 'relevanssi_ajax_index_pdf' );
/**
* Performs the "list PDF files" AJAX action.
*
* Uses relevanssi_get_posts_with_attachments() to get a list of posts with files
* attached to them.
*
* @since 2.0.0
*/
function relevanssi_list_pdfs_action() {
check_ajax_referer( 'relevanssi-list-pdfs', 'security' );
relevanssi_current_user_can_access_options();
$limit = 0;
if ( isset( $_POST['limit'] ) ) { // WPCS: input var ok.
$limit = intval( wp_unslash( $_POST['limit'] ) ); // WPCS: input var ok.
}
$pdfs = relevanssi_get_posts_with_attachments( $limit );
echo wp_json_encode( $pdfs );
wp_die();
}
/**
* Performs the "wipe PDF content" AJAX action.
*
* Removes all '_relevanssi_pdf_content' and '_relevanssi_pdf_error' post meta
* fields from the wp_postmeta table. However, if '_relevanssi_pdf_modified' is
* set, the content is not removed for that post.
*
* @since 2.0.0
*/
function relevanssi_wipe_pdfs_action() {
check_ajax_referer( 'relevanssi-wipe-pdfs', 'security' );
relevanssi_current_user_can_access_options();
$deleted_content = relevanssi_delete_all_but(
'_relevanssi_pdf_content',
'_relevanssi_pdf_modified',
'1'
);
$deleted_errors = delete_post_meta_by_key( '_relevanssi_pdf_error' );
$response = array();
$response['deleted_content'] = false;
$response['deleted_errors'] = false;
if ( $deleted_content ) {
$response['deleted_content'] = true;
}
if ( $deleted_errors ) {
$response['deleted_errors'] = true;
}
echo wp_json_encode( $response );
wp_die();
}
/**
* Deletes all post meta for certain meta key unless another meta key is set.
*
* @global object $wpdb The WordPress database interface.
*
* @param string $meta_key The meta key to delete.
* @param string $exclusion_key The conditional meta key.
* @param string $value Value for the conditional meta to check.
*
* @return boolean True if something was deleted, false if not.
*
* @since 2.5.0
*/
function relevanssi_delete_all_but( $meta_key, $exclusion_key, $value ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = %s
AND post_id NOT IN (
SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s
)",
$meta_key,
$exclusion_key,
$value
);
$meta_ids = $wpdb->get_col( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( ! count( $meta_ids ) ) {
return false;
}
$query = "DELETE FROM $wpdb->postmeta WHERE meta_id IN ( " . implode( ',', $meta_ids ) . ' )';
$count = $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( ! $count ) {
return false;
}
return true;
}
/**
* Performs the "index PDFs" AJAX action.
*
* Reads in the PDF content for PDF files fetched using the relevanssi_get_posts_with_attachments() function.
*
* @since 2.0.0
*/
function relevanssi_index_pdfs_action() {
check_ajax_referer( 'relevanssi-index-pdfs', 'security' );
relevanssi_current_user_can_access_options();
$pdfs = relevanssi_get_posts_with_attachments( 3 );
if ( ! isset( $_POST['completed'] ) || ! isset( $_POST['total'] ) ) { // WPCS: input var ok.
wp_die();
}
$post_data = $_POST; // WPCS: input var ok.
$completed = absint( $post_data['completed'] );
$total = absint( $post_data['total'] );
$response = array();
$response['feedback'] = '';
if ( empty( $pdfs ) ) {
$response['feedback'] = __( 'Indexing complete!', 'relevanssi' );
$response['completed'] = 'done';
$response['percentage'] = 100;
} else {
foreach ( $pdfs as $post_id ) {
$echo_and_die = false;
$send_files = get_option( 'relevanssi_send_pdf_files' );
if ( 'off' === $send_files ) {
$send_files = false;
}
$index_response = relevanssi_index_pdf( $post_id, $echo_and_die, $send_files );
$completed++;
if ( $index_response['success'] ) {
// translators: placeholder is the post ID.
$response['feedback'] .= sprintf( esc_html__( 'Successfully indexed attachment id %d.', 'relevanssi' ), esc_html( $post_id ) ) . "\n";
} else {
// translators: the numeric placeholder is the post ID, the string is the error message.
$response['feedback'] .= sprintf( esc_html__( 'Failed to index attachment id %1$d: %2$s', 'relevanssi' ), esc_html( $post_id ), esc_html( $index_response['error'] ) ) . "\n";
}
}
$response['completed'] = $completed;
if ( $total > 0 ) {
$response['percentage'] = round( $completed / $total * 100, 0 );
} else {
$response['percentage'] = 0;
}
}
echo wp_json_encode( $response );
wp_die();
}
/**
* Performs the "send PDF" AJAX action.
*
* Reads in the PDF content for one PDF file, based on the 'post_id' parameter, sending the PDF over.
*
* @since 2.0.0
*/
function relevanssi_send_pdf() {
check_ajax_referer( 'relevanssi_send_pdf', 'security' );
if ( ! current_user_can( 'upload_files' ) ) {
wp_die();
}
if ( ! isset( $_REQUEST['post_id'] ) ) { // WPCS: input var ok.
wp_die();
}
$post_id = intval( wp_unslash( $_REQUEST['post_id'] ) ); // WPCS: input var ok.
$echo_and_die = true;
$send_file = true;
relevanssi_index_pdf( $post_id, $echo_and_die, $send_file );
// Just for sure; relevanssi_index_pdf() should echo necessary responses and die, so don't expect this to ever happen.
wp_die();
}
/**
* Performs the "send URL" AJAX action.
*
* Reads in the PDF content for one PDF file, based on the 'post_id' parameter, using the PDF URL.
*
* @since 2.0.0
*/
function relevanssi_send_url() {
check_ajax_referer( 'relevanssi_send_pdf', 'security' );
if ( ! current_user_can( 'upload_files' ) ) {
wp_die();
}
if ( ! isset( $_REQUEST['post_id'] ) ) { // WPCS: input var ok.
wp_die();
}
$post_id = intval( wp_unslash( $_REQUEST['post_id'] ) ); // WPCS: input var ok.
$echo_and_die = true;
$send_file = false;
relevanssi_index_pdf( $post_id, $echo_and_die, $send_file );
// Just for sure; relevanssi_index_pdf() should echo necessary responses and die, so don't expect this to ever happen.
wp_die();
}
/**
* Reads all PDF errors.
*
* Gets a list of all PDF errors in the database and prints out a list of them.
*
* @global $wpdb The WordPress database interface, used to fetch the meta fields.
*
* @since 2.0.0
*/
function relevanssi_get_pdf_errors_action() {
if ( ! current_user_can( 'upload_files' ) ) {
wp_die();
}
global $wpdb;
$errors = $wpdb->get_results( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_relevanssi_pdf_error'" );
$error_message = array();
foreach ( $errors as $error ) {
$row = __( 'Attachment ID', 'relevanssi' ) . ' ' . $error->post_id . ': ' . $error->meta_value;
$row = str_replace( 'PDF Processor error: ', '', $row );
$error_message[] = $row;
}
echo wp_json_encode( implode( "\n", $error_message ) );
wp_die();
}
/**
* Reads a list of taxonomies.
*
* Gets a list of taxonomies selected for indexing from the relevanssi_list_taxonomies() function.
*
* @since 2.0.0
*/
function relevanssi_list_taxonomies_wrapper() {
relevanssi_current_user_can_access_options();
$taxonomies = array();
if ( function_exists( 'relevanssi_list_taxonomies' ) ) {
$taxonomies = relevanssi_list_taxonomies();
}
echo wp_json_encode( $taxonomies );
wp_die();
}
/**
* Indexes taxonomy terms for AJAX indexing.
*
* Reads in the parameters, indexes taxonomy terms and reports the results.
*
* @since 2.0.0
*/
function relevanssi_index_taxonomies_ajax_wrapper() {
check_ajax_referer( 'relevanssi_taxonomy_indexing_nonce', 'security' );
relevanssi_current_user_can_access_options();
if ( ! isset( $_POST['completed'] ) || ! isset( $_POST['total'] ) || ! isset( $_POST['taxonomy'] ) || ! isset( $_POST['offset'] ) || ! isset( $_POST['limit'] ) ) { // WPCS: input var ok.
wp_die();
}
$post_data = $_POST; // WPCS: input var ok.
$completed = absint( $post_data['completed'] );
$total = absint( $post_data['total'] );
$taxonomy = $post_data['taxonomy'];
$offset = $post_data['offset'];
$limit = $post_data['limit'];
$response = array();
$indexing_response = relevanssi_index_taxonomies_ajax( $taxonomy, $limit, $offset );
$completed += $indexing_response['indexed'];
if ( $completed === $total ) {
$response['completed'] = 'done';
$response['total_posts'] = $completed;
$response['percentage'] = 100;
// translators: number of terms indexed on this go, total indexed terms, total number of terms.
$response['feedback'] = sprintf( _n( '%1$d taxonomy term, total %2$d / %3$d.', '%1$d taxonomy terms, total %2$d / %3$d.', $indexing_response['indexed'], 'relevanssi' ), $indexing_response['indexed'], $completed, $total ) . "\n";
} else {
$response['completed'] = $completed;
// translators: number of terms indexed on this go, total indexed terms, total number of terms.
$response['feedback'] = sprintf( _n( '%1$d taxonomy term, total %2$d / %3$d.', '%1$d taxonomy terms, total %2$d / %3$d.', $indexing_response['indexed'], 'relevanssi' ), $indexing_response['indexed'], $completed, $total ) . "\n";
if ( $total > 0 ) {
$response['percentage'] = $completed / $total * 100;
} else {
$response['percentage'] = 0;
}
$response['new_taxonomy'] = false;
if ( 'done' === $indexing_response['taxonomy_completed'] ) {
$response['new_taxonomy'] = true;
}
}
$response['offset'] = $offset + $limit;
echo wp_json_encode( $response );
wp_die();
}
/**
* Indexes post type archives for AJAX indexing.
*
* Indexes post type archives and reports the results. The post type archives are
* always indexed all at one go; I don't think there's often a case where there are
* too many.
*
* @since 2.2.0
*/
function relevanssi_index_post_type_archives_ajax_wrapper() {
check_ajax_referer( 'relevanssi_post_type_archive_indexing_nonce', 'security' );
relevanssi_current_user_can_access_options();
$response = array();
if ( 'on' !== get_option( 'relevanssi_index_post_type_archives' ) ) {
$response['feedback'] = __( 'disabled.', 'relevanssi' ) . "\n";
} else {
$indexing_response = relevanssi_index_post_type_archives_ajax();
$response['completed'] = 'done';
$response['total_posts'] = $indexing_response['indexed'];
$response['percentage'] = 100;
// translators: number of terms indexed on this go, total indexed terms, total number of terms.
$response['feedback'] = sprintf( _n( '%1$d post type archive indexed.', '%1$d post type archives indexed.', $indexing_response['indexed'], 'relevanssi' ), $indexing_response['indexed'] ) . "\n";
}
echo wp_json_encode( $response );
wp_die();
}
/**
* Indexes users for AJAX indexing.
*
* Reads in the parameters, indexes users and reports the results.
*
* @since 2.0.0
*/
function relevanssi_index_users_ajax_wrapper() {
check_ajax_referer( 'relevanssi_user_indexing_nonce', 'security' );
relevanssi_current_user_can_access_options();
if ( ! isset( $_POST['completed'] ) || ! isset( $_POST['total'] ) || ! isset( $_POST['limit'] ) ) { // WPCS: input var ok.
wp_die();
}
$post_data = $_POST; // WPCS: input var ok.
$completed = absint( $post_data['completed'] );
$total = absint( $post_data['total'] );
$limit = $post_data['limit'];
if ( isset( $post_data['offset'] ) ) {
$offset = $post_data['offset'];
} else {
$offset = 0;
}
$response = array();
$indexing_response = relevanssi_index_users_ajax( $limit, $offset );
$completed += $indexing_response['indexed'];
$processed = $offset;
if ( $completed === $total || $processed > $total ) {
$response['completed'] = 'done';
$response['total_posts'] = $completed;
$response['percentage'] = 100;
$processed = $total;
} else {
$response['completed'] = $completed;
$offset = $offset + $limit;
if ( $total > 0 ) {
$response['percentage'] = $completed / $total * 100;
} else {
$response['percentage'] = 0;
}
}
// translators: number of users indexed on this go, total indexed users, total processed users, total number of users.
$response['feedback'] = sprintf( _n( 'Indexed %1$d user (total %2$d), processed %3$d / %4$d.', 'Indexed %1$d users (total %2$d), processed %3$d / %4$d.', $indexing_response['indexed'], 'relevanssi' ), $indexing_response['indexed'], $completed, $processed, $total ) . "\n";
$response['offset'] = $offset;
echo wp_json_encode( $response );
wp_die();
}
/**
* Counts the users.
*
* Counts the users for indexing purposes using the relevanssi_count_users() function.
*
* @since 2.0.0
*/
function relevanssi_count_users_ajax_wrapper() {
relevanssi_current_user_can_access_options();
$count = -1;
if ( function_exists( 'relevanssi_count_users' ) ) {
$count = relevanssi_count_users();
}
echo wp_json_encode( $count );
wp_die();
}
/**
* Counts the taxonomy terms.
*
* Counts the taxonomy terms for indexing purposes using the relevanssi_count_taxonomy_terms() function.
*
* @since 2.0.0
*/
function relevanssi_count_taxonomies_ajax_wrapper() {
relevanssi_current_user_can_access_options();
$count = -1;
if ( function_exists( 'relevanssi_count_taxonomy_terms' ) ) {
$count = relevanssi_count_taxonomy_terms();
}
echo wp_json_encode( $count );
wp_die();
}
/**
* Creates a list of related posts.
*
* @since 2.2.4
*/
function relevanssi_get_related_posts() {
check_ajax_referer( 'relevanssi_metabox_nonce', 'security' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die();
}
$post_id = (int) $_POST['post_id']; // WPCS: input var ok.
if ( 0 === $post_id ) {
wp_die();
}
if ( isset( $_POST['keywords'] ) ) {
$keywords = sanitize_text_field( $_POST['keywords'] ); // WPCS: input var ok.
delete_post_meta( $post_id, '_relevanssi_related_keywords' );
add_post_meta( $post_id, '_relevanssi_related_keywords', $keywords );
// Keywords have changed, flush the cache.
delete_post_meta( $post_id, '_relevanssi_related_posts' );
}
if ( isset( $_POST['ids'] ) ) {
$include_ids_array = explode( ',', $_POST['ids'] );
$valid_ids = array();
foreach ( $include_ids_array as $id ) {
if ( get_post( $id ) ) {
$valid_ids[] = $id;
}
}
if ( ! empty( $valid_ids ) ) {
$id_string = implode( ',', $valid_ids );
delete_post_meta( $post_id, '_relevanssi_related_include_ids' );
add_post_meta( $post_id, '_relevanssi_related_include_ids', $id_string );
} else {
delete_post_meta( $post_id, '_relevanssi_related_include_ids' );
}
// Included IDs have changed, flush the cache.
delete_post_meta( $post_id, '_relevanssi_related_posts' );
}
$list = relevanssi_generate_related_list( $post_id );
$response = array(
'list' => $list,
);
echo wp_json_encode( $response );
wp_die();
}
/**
* Adds a post ID to the excluded ID list.
*
* @since 2.2.4
*/
function relevanssi_add_to_exclude_list() {
check_ajax_referer( 'relevanssi_metabox_nonce', 'security' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die();
}
$post_id = (int) $_POST['post_id']; // WPCS: input var ok.
if ( 0 === $post_id ) {
wp_die();
}
if ( isset( $_POST['remove_id'] ) ) {
relevanssi_exclude_a_related_post( $post_id, $_POST['remove_id'] );
}
$related = relevanssi_generate_related_list( $post_id );
$excluded = relevanssi_generate_excluded_list( $post_id );
$response = array(
'related' => $related,
'excluded' => $excluded,
);
echo wp_json_encode( $response );
wp_die();
}
/**
* Adds a post ID to the list of excluded post IDs of a post.
*
* @param int $post_id Add to this post IDs exclude list.
* @param int $excluded_post Add this post ID to the exclude list.
*/
function relevanssi_exclude_a_related_post( $post_id, $excluded_post ) {
$remove_id = (int) $excluded_post;
$excluded_ids = trim( get_post_meta( $post_id, '_relevanssi_related_exclude_ids', true ) );
if ( $excluded_ids ) {
$excluded_ids = explode( ',', $excluded_ids );
} else {
$excluded_ids = array();
}
$excluded_ids[] = $remove_id;
$excluded_ids = array_keys( array_flip( $excluded_ids ) );
$excluded_ids = implode( ',', $excluded_ids );
update_post_meta( $post_id, '_relevanssi_related_exclude_ids', $excluded_ids );
// Excluded IDs have changed, flush the cache.
delete_post_meta( $post_id, '_relevanssi_related_posts' );
}
/**
* Removes a post ID from the excluded ID list and regenerates the lists.
*
* @since 2.2.4
*/
function relevanssi_remove_from_exclude_list() {
check_ajax_referer( 'relevanssi_metabox_nonce', 'security' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die();
}
$post_id = (int) $_POST['post_id']; // WPCS: input var ok.
if ( 0 === $post_id ) {
wp_die();
}
if ( isset( $_POST['return_id'] ) ) {
relevanssi_unexclude_a_related_post( $post_id, $_POST['return_id'] );
}
$related = relevanssi_generate_related_list( $post_id );
$excluded = relevanssi_generate_excluded_list( $post_id );
$response = array(
'related' => $related,
'excluded' => $excluded,
);
echo wp_json_encode( $response );
wp_die();
}
/**
* Removes a post ID from the related posts exclude list.
*
* @param int $post_id The post ID that owns the related posts exclude list.
* @param int $unexcluded_post The post ID which is removed from the exclude list.
*/
function relevanssi_unexclude_a_related_post( $post_id, $unexcluded_post ) {
$return_id = (int) $unexcluded_post;
$excluded_ids = trim( get_post_meta( $post_id, '_relevanssi_related_exclude_ids', true ) );
$excluded_ids = array_flip( explode( ',', $excluded_ids ) );
unset( $excluded_ids[ $return_id ] );
$excluded_ids = array_keys( $excluded_ids );
$excluded_ids = implode( ',', $excluded_ids );
update_post_meta( $post_id, '_relevanssi_related_exclude_ids', $excluded_ids );
// Excluded IDs have changed, flush the cache.
delete_post_meta( $post_id, '_relevanssi_related_posts' );
}
/**
* Adds a keyword to the pinned keywords list for a post.
*
* @since 2.2.6
*/
function relevanssi_pin_post() {
check_ajax_referer( 'relevanssi_admin_search_nonce', 'security' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die();
}
$post_id = (int) $_POST['post_id']; // WPCS: input var ok.
$keyword = $_POST['keyword']; // WPCS: input var ok.
if ( 0 === $post_id || empty( $keyword ) ) {
wp_die();
}
$result = false;
$already_pinned = false;
$pins = get_post_meta( $post_id, '_relevanssi_pin' );
foreach ( $pins as $pin ) {
if ( $pin === $keyword ) {
$already_pinned = true;
break;
}
}
if ( ! $already_pinned ) {
$result = add_post_meta( $post_id, '_relevanssi_pin', $keyword );
}
$response = array(
'success' => $result,
);
echo wp_json_encode( $response );
wp_die();
}
/**
* Removes a keyword from the pinned keywords list for a post.
*
* @since 2.2.6
*/
function relevanssi_unpin_post() {
check_ajax_referer( 'relevanssi_admin_search_nonce', 'security' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die();
}
$post_id = (int) $_POST['post_id']; // WPCS: input var ok.
$keyword = $_POST['keyword']; // WPCS: input var ok.
if ( 0 === $post_id || empty( $keyword ) ) {
wp_die();
}
$result = delete_post_meta( $post_id, '_relevanssi_pin', $keyword );
$response = array(
'success' => $result,
);
echo wp_json_encode( $response );
wp_die();
}
/**
* Fetches database words to the relevanssi_words option.
*
* An AJAX wrapper for relevanssi_update_words_option().
*
* @see relevanssi_update_words_option()
*
* @since 2.5.0
*/
function relevanssi_ajax_get_words() {
if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'relevanssi_get_words' ) ) {
wp_die();
}
relevanssi_update_words_option();
wp_die();
}
/**
* Launches the attachment content indexing.
*
* Sets the _relevanssi_pdf_error for the post to show RELEVANSSI_ERROR_05
* (ie. "work in progress"), then launches the indexing and dies off.
*
* @since 2.5.0
*/
function relevanssi_ajax_index_pdf() {
if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'relevanssi_index_pdf' ) ) {
wp_die();
}
if ( ! current_user_can( 'upload_files' ) ) {
wp_die();
}
update_post_meta( $_REQUEST['post_id'], '_relevanssi_pdf_error', RELEVANSSI_ERROR_05 );
relevanssi_index_pdf( $_REQUEST['post_id'] );
wp_die();
}

View File

@@ -1,71 +0,0 @@
jQuery(document).ready(function ($) {
$("#relevanssi_related_keywords").change(function (e) {
var post_id = $("#this_post_id").val()
var keywords = $("#relevanssi_related_keywords").val()
var data = {
action: "relevanssi_related_posts",
security: relevanssi_metabox_data.metabox_nonce,
post_id: post_id,
keywords: keywords,
}
jQuery.post(ajaxurl, data, function (response) {
response = JSON.parse(response)
$("#related_posts_list").html(response.list)
})
})
$("#relevanssi_related_include_ids").change(function (e) {
var post_id = $("#this_post_id").val()
var ids = $("#relevanssi_related_include_ids").val()
var data = {
action: "relevanssi_related_posts",
security: relevanssi_metabox_data.metabox_nonce,
post_id: post_id,
ids: ids,
}
jQuery.post(ajaxurl, data, function (response) {
response = JSON.parse(response)
$("#related_posts_list").html(response.list)
})
})
$("#relevanssi_hidebox").on("click", "button.removepost", function (e) {
var remove_id = $(this).data("removepost")
if (remove_id) {
var post_id = $("#this_post_id").val()
var data = {
action: "relevanssi_related_remove",
security: relevanssi_metabox_data.metabox_nonce,
post_id: post_id,
remove_id: remove_id,
}
jQuery.post(ajaxurl, data, function (response) {
response = JSON.parse(response)
$("#related_posts_list").html(response.related)
$("#excluded_posts_list").html(response.excluded)
})
}
})
$("#relevanssi_hidebox").on("click", "button.returnpost", function (e) {
var return_id = $(this).data("returnpost")
console.log(return_id)
if (return_id) {
var post_id = $("#this_post_id").val()
var data = {
action: "relevanssi_related_return",
security: relevanssi_metabox_data.metabox_nonce,
post_id: post_id,
return_id: return_id,
}
jQuery.post(ajaxurl, data, function (response) {
response = JSON.parse(response)
console.log(response)
$("#related_posts_list").html(response.related)
$("#excluded_posts_list").html(response.excluded)
})
}
})
})

View File

@@ -1,49 +0,0 @@
jQuery(document).ready(function () {
jQuery("#sendUrl").click(function (e) {
e.preventDefault()
var postID = jQuery("#sendUrl").data("post_id")
console.log(postID)
jQuery.ajax({
url: ajaxurl,
type: "POST",
data: {
action: "relevanssi_send_url",
post_id: postID,
security: admin_pdf_data.send_pdf_nonce,
},
dataType: "json",
complete: function (data) {
console.log(data)
location.reload()
},
})
})
jQuery("#sendPdf").click(function (e) {
e.preventDefault()
var postID = jQuery("#sendPdf").data("post_id")
console.log(postID)
jQuery.ajax({
url: ajaxurl,
type: "POST",
data: {
action: "relevanssi_send_pdf",
post_id: postID,
security: admin_pdf_data.send_pdf_nonce,
},
dataType: "json",
complete: function (data) {
console.log(data)
location.reload()
},
})
})
jQuery("textarea#relevanssi_pdf_content").focus(function () {
jQuery(this).animate({ rows: 40, cols: 120 }, 500)
})
jQuery("textarea#relevanssi_pdf_content").focusout(function () {
jQuery(this).animate({ rows: 4, cols: 80 }, 500)
})
})

View File

@@ -1,540 +0,0 @@
jQuery(document).ready(function ($) {
// Show and hide the "Show Relevanssi for admins" setting on the Overview tab depending
// on whether the "Hide Relevanssi" setting is enabled.
var show_post_controls = $("#show_post_controls")
$("#relevanssi_hide_post_controls").change(function () {
show_post_controls.toggleClass("screen-reader-text")
})
// Find out the latest row ID in the redirect table.
var last_row_id = $(".redirect_table_row:last").attr("id")
var redirect_row_index = 0
if (last_row_id) {
// There's a last row, we're on the Redirects tab.
last_row_id = last_row_id.split("_")
if (last_row_id.length > 1) {
redirect_row_index = last_row_id[1]
}
}
// Adds a new row to the redirect table on the Redirects tab.
$("#add_redirect").click(function (e) {
redirect_row_index++
$(".redirect_table_row:last")
.clone(true)
.attr("id", "row_" + redirect_row_index)
.insertAfter(".redirect_table_row:last")
var query = $("#row_" + redirect_row_index + " input:first")
query.val("")
query.attr("name", "query_" + redirect_row_index)
query.attr("id", "query_" + redirect_row_index)
var partial = $("#row_" + redirect_row_index + " input:checkbox")
partial.prop("checked", false)
partial.attr("name", "partial_" + redirect_row_index)
partial.attr("id", "partial_" + redirect_row_index)
var url = $("#row_" + redirect_row_index + " input:eq(2)")
url.val("")
url.attr("id", "url_" + redirect_row_index)
url.attr("name", "url_" + redirect_row_index)
var hits = $("#row_" + redirect_row_index + " input:last")
hits.val("")
hits.attr("name", "hits_" + redirect_row_index)
hits.attr("id", "hits_" + redirect_row_index)
var hitsNumber = $("#row_" + redirect_row_index + " span:last")
hitsNumber.html("0")
})
// Related posts tab: if "Matching post types" is checked, disable and uncheck other options.
$("input.matching").click(function (e) {
if ($(this).is(":checked")) {
$("input.nonmatching").prop("checked", false)
$("input.nonmatching").attr("disabled", true)
} else {
$("input.nonmatching").attr("disabled", false)
}
})
// Related posts tab: Display default thumbnail option.
$("#relevanssi_related_thumbnails").click(function (e) {
$("#defaultthumbnail").toggleClass("screen-reader-text", !this.checked)
})
// Redirects tab redirect table row removal.
$(".remove").click(function (e) {
e.preventDefault()
if ($("#redirect_table >tbody >tr").length > 1) {
// If there is more than one row in the table, remove the last row.
$(this).closest("tr").remove()
} else {
// Only one row left, don't remove it (because adding rows is based on cloning).
// Instead empty out the values.
$(".redirect_table_row:last input:text").val("")
$(".redirect_table_row:last input:checkbox").prop("checked", false)
}
})
// Related posts tab: Toggle settings for main switch.
$("#relevanssi_related_enabled").click(function () {
$("#tr_relevanssi_related_append input").attr("disabled", !this.checked)
$("#tr_relevanssi_related_keyword input").attr("disabled", !this.checked)
$("#relevanssi_related_number").attr("disabled", !this.checked)
$("#relevanssi_related_months").attr("disabled", !this.checked)
$("#tr_relevanssi_related_post_types input").attr("disabled", !this.checked)
$("#relevanssi_related_nothing").attr("disabled", !this.checked)
$("#relevanssi_related_notenough").attr("disabled", !this.checked)
$("#relevanssi_related_titles").attr("disabled", !this.checked)
$("#relevanssi_related_thumbnails").attr("disabled", !this.checked)
$("#relevanssi_related_excerpts").attr("disabled", !this.checked)
$("#relevanssi_related_cache_for_admins").attr("disabled", !this.checked)
$("#relevanssi_flush_related_cache").attr("disabled", !this.checked)
})
// Redirects tab redirect table row cloning.
$("a.copy").click(function (e) {
e.preventDefault()
redirect_row_index++
$(this)
.closest("tr")
.clone(true)
.attr("id", "row_" + redirect_row_index)
.insertAfter(".redirect_table_row:last")
var query = $("#row_" + redirect_row_index + " input:first")
query.attr("name", "query_" + redirect_row_index)
query.attr("id", "query_" + redirect_row_index)
var partial = $("#row_" + redirect_row_index + " input:checkbox")
partial.attr("name", "partial_" + redirect_row_index)
partial.attr("id", "partial_" + redirect_row_index)
var url = $("#row_" + redirect_row_index + " input:eq(2)")
url.attr("name", "url_" + redirect_row_index)
url.attr("name", "url_" + redirect_row_index)
var hits = $("#row_" + redirect_row_index + " input:last")
hits.val("")
hits.attr("name", "hits_" + redirect_row_index)
hits.attr("id", "hits_" + redirect_row_index)
var hitsNumber = $("#row_" + redirect_row_index + " span:last")
hitsNumber.html("0")
})
$("#attachments_tab :input").change(function (e) {
$("#index").attr("disabled", "disabled")
var relevanssi_note = $("#relevanssi-note")
relevanssi_note.show()
relevanssi_note.html(
'<p class="description important">' + relevanssi.options_changed + "</p>"
)
})
$("#build_index").click(function () {
$("#relevanssi-progress").show()
$("#results").show()
$("#relevanssi-timer").show()
$("#relevanssi-indexing-instructions").show()
$("#stateoftheindex").html(relevanssi.reload_state)
$("#indexing_button_instructions").hide()
var results = document.getElementById("results")
results.value = ""
var data = {
action: "relevanssi_truncate_index",
security: nonce.indexing_nonce,
}
intervalID = window.setInterval(relevanssiUpdateClock, 1000)
console.log("Truncating index.")
results.value += relevanssi.truncating_index + " "
jQuery.post(ajaxurl, data, function (response) {
truncate_response = JSON.parse(response)
console.log("Truncate index: " + truncate_response)
if (truncate_response == true) {
results.value += relevanssi.done + "\n"
}
var data = {
action: "relevanssi_index_post_type_archives",
security: nonce.post_type_archive_indexing_nonce,
}
console.log("Indexing post type archives.")
results.value += "Indexing post type archives... "
jQuery.post(ajaxurl, data, function (response) {
console.log("Done")
response = JSON.parse(response)
results.value += response.feedback
var data = {
action: "relevanssi_count_users",
}
console.log("Counting users.")
results.value += relevanssi.counting_users + " "
jQuery.post(ajaxurl, data, function (response) {
count_response = JSON.parse(response)
console.log("Counted " + count_response + " users.")
if (count_response < 0) {
results.value += relevanssi.user_disabled + "\n"
} else {
results.value +=
count_response + " " + relevanssi.users_found + "\n"
}
var user_total = count_response
var data = {
action: "relevanssi_count_taxonomies",
}
console.log("Counting taxonomies.")
results.value += relevanssi.counting_terms + " "
jQuery.post(ajaxurl, data, function (response) {
count_response = JSON.parse(response)
console.log("Counted " + count_response + " taxonomy terms.")
if (count_response < 0) {
results.value += relevanssi.taxonomy_disabled + "\n"
} else {
results.value +=
count_response + " " + relevanssi.terms_found + "\n"
}
var taxonomy_total = count_response
var data = {
action: "relevanssi_count_posts",
}
console.log("Counting posts.")
results.value += relevanssi.counting_posts + " "
jQuery.post(ajaxurl, data, function (response) {
count_response = JSON.parse(response)
console.log("Counted " + count_response + " posts.")
var post_total = parseInt(count_response)
results.value +=
count_response + " " + relevanssi.posts_found + "\n"
var data = {
action: "relevanssi_list_taxonomies",
}
console.log("Listing taxonomies.")
jQuery.post(ajaxurl, data, function (response) {
taxonomies_response = JSON.parse(response)
console.log("Listing taxonomies: " + taxonomies_response)
console.log("Starting indexing.")
console.log("User total " + user_total)
if (user_total > 0) {
console.log("Indexing users.")
var args = {
total: user_total,
completed: 0,
total_seconds: 0,
post_total: post_total,
limit: 10,
taxonomies: taxonomies_response,
taxonomies_total: taxonomy_total,
}
process_user_step(args)
} else if (taxonomy_total > 0) {
console.log("Indexing taxonomies.")
results.value += relevanssi.indexing_taxonomies + " "
results.value += taxonomies_response + "\n"
var args = {
taxonomies: taxonomies_response,
completed: 0,
total: taxonomy_total,
total_seconds: 0,
post_total: post_total,
current_taxonomy: "",
offset: 0,
limit: 20,
}
process_taxonomy_step(args)
} else {
console.log("Just indexing.")
var args = {
completed: 0,
total: post_total,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: false,
security: nonce.indexing_nonce,
}
process_indexing_step(args)
}
})
})
})
})
})
})
})
})
function process_user_step(args) {
var completed = args.completed
var total = args.total
var total_seconds = args.total_seconds
console.log(completed + " / " + total)
var t0 = performance.now()
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_index_users",
limit: args.limit,
offset: args.offset,
completed: completed,
total: total,
security: nonce.user_indexing_nonce,
},
dataType: "json",
success: function (response) {
console.log(response)
if (response.completed == "done") {
var t1 = performance.now()
var time_seconds = (t1 - t0) / 1000
time_seconds = Math.round(time_seconds * 100) / 100
total_seconds += time_seconds
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
results_textarea.scrollTop = results_textarea.scrollHeight
var percentage_rounded = Math.round(response.percentage)
jQuery(".rpi-progress div").animate(
{
width: percentage_rounded + "%",
},
50,
function () {
// Animation complete.
}
)
console.log("Done indexing users.")
if (args.taxonomies_total > 0) {
var new_args = {
completed: 0,
total: args.taxonomies_total,
taxonomies: args.taxonomies,
current_taxonomy: "",
post_total: args.post_total,
offset: 0,
total_seconds: total_seconds,
limit: 20,
extend: false,
}
process_taxonomy_step(new_args)
} else {
var new_args = {
security: nonce.indexing_nonce,
completed: 0,
total: args.post_total,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: false,
}
process_indexing_step(new_args)
}
} else {
var t1 = performance.now()
var time_seconds = (t1 - t0) / 1000
time_seconds = Math.round(time_seconds * 100) / 100
total_seconds += time_seconds
var estimated_time = rlv_format_approximate_time(
Math.round(
(total_seconds / response.percentage) * 100 - total_seconds
)
)
document.getElementById("relevanssi_estimated").innerHTML =
estimated_time
if (time_seconds < 2) {
args.limit = args.limit * 2
// current limit can be indexed in less than two seconds; double the limit
} else if (time_seconds < 5) {
args.limit += 5
// current limit can be indexed in less than five seconds; up the limit
} else if (time_seconds > 20) {
args.limit = Math.round(args.limit / 2)
if (args.limit < 1) args.limit = 1
// current limit takes more than twenty seconds; halve the limit
} else if (time_seconds > 10) {
args.limit -= 5
if (args.limit < 1) args.limit = 1
// current limit takes more than ten seconds; reduce the limit
}
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
results_textarea.scrollTop = results_textarea.scrollHeight
var percentage_rounded = Math.round(response.percentage)
jQuery(".rpi-progress div").animate(
{
width: percentage_rounded + "%",
},
50,
function () {
// Animation complete.
}
)
console.log("Next step.")
var new_args = {
completed: parseInt(response.completed),
total: args.total,
total_seconds: total_seconds,
offset: response.offset,
limit: args.limit,
post_total: args.post_total,
taxonomies: args.taxonomies,
taxonomies_total: args.taxonomies_total,
}
process_user_step(new_args)
}
},
})
}
function process_taxonomy_step(args) {
var completed = args.completed
var total = args.total
var total_seconds = args.total_seconds
console.log(completed + " / " + total)
var t0 = performance.now()
if (args.current_taxonomy == "") {
taxonomy = args.taxonomies.shift()
args.offset = 0
args.limit = 20
} else {
taxonomy = args.current_taxonomy
}
if (taxonomy != undefined) {
var results_textarea = document.getElementById("results")
results_textarea.value += "Indexing " + "'" + taxonomy + "': "
jQuery.ajax({
type: "POST",
url: ajaxurl,
data: {
action: "relevanssi_index_taxonomies",
completed: completed,
total: total,
taxonomy: taxonomy,
offset: args.offset,
limit: args.limit,
security: nonce.taxonomy_indexing_nonce,
},
dataType: "json",
success: function (response) {
console.log(response)
if (response.completed == "done") {
var t1 = performance.now()
var time_seconds = (t1 - t0) / 1000
time_seconds = Math.round(time_seconds * 100) / 100
total_seconds += time_seconds
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
console.log("Done indexing taxonomies.")
var new_args = {
completed: 0,
total: args.post_total,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: false,
security: nonce.indexing_nonce,
}
process_indexing_step(new_args)
} else {
var t1 = performance.now()
var time_seconds = (t1 - t0) / 1000
time_seconds = Math.round(time_seconds * 100) / 100
total_seconds += time_seconds
var estimated_time = rlv_format_approximate_time(
Math.round(
(total_seconds / response.percentage) * 100 - total_seconds
)
)
document.getElementById("relevanssi_estimated").innerHTML =
estimated_time
if (time_seconds < 2) {
args.limit = args.limit * 2
// current limit can be indexed in less than two seconds; double the limit
} else if (time_seconds < 5) {
args.limit += 5
// current limit can be indexed in less than five seconds; up the limit
} else if (time_seconds > 20) {
args.limit = Math.round(args.limit / 2)
if (args.limit < 1) args.limit = 1
// current limit takes more than twenty seconds; halve the limit
} else if (time_seconds > 10) {
args.limit -= 5
if (args.limit < 1) args.limit = 1
// current limit takes more than ten seconds; reduce the limit
}
var results_textarea = document.getElementById("results")
results_textarea.value += response.feedback
results_textarea.scrollTop = results_textarea.scrollHeight
var percentage_rounded = Math.round(response.percentage)
jQuery(".rpi-progress div").animate(
{
width: percentage_rounded + "%",
},
50,
function () {
// Animation complete.
}
)
console.log("Next step.")
if (response.new_taxonomy) taxonomy = ""
var new_args = {
taxonomies: args.taxonomies,
completed: parseInt(response.completed),
total: args.total,
total_seconds: total_seconds,
post_total: args.post_total,
current_taxonomy: taxonomy,
offset: response.offset,
limit: args.limit,
}
process_taxonomy_step(new_args)
}
},
})
} else {
var new_args = {
completed: 0,
total: args.post_total,
offset: 0,
total_seconds: 0,
limit: relevanssi_params.indexing_limit,
adjust: relevanssi_params.indexing_adjust,
extend: false,
security: nonce.indexing_nonce,
}
process_indexing_step(new_args)
}
}

View File

@@ -1,388 +0,0 @@
<?php
/**
* /premium/body-stopwords.php
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_match', 'relevanssi_block_body_stopwords', 10, 3 );
/**
* Adds a stopword to the list of stopwords.
*
* @param string $term The stopword that is added.
* @param boolean $verbose If true, print out notice. If false, be silent. Default
* true.
*
* @return boolean True, if success; false otherwise.
*/
function relevanssi_add_body_stopword( $term, $verbose = true ) {
if ( empty( $term ) ) {
return;
}
$n = 0;
$s = 0;
$terms = explode( ',', $term );
if ( count( $terms ) > 1 ) {
foreach ( $terms as $term ) {
$n++;
$term = trim( $term );
$success = relevanssi_add_single_body_stopword( $term );
if ( $success ) {
$s++;
}
}
if ( $verbose ) {
// translators: %1$d is the successful entries, %2$d is the total entries.
printf( "<div id='message' class='updated fade'><p>%s</p></div>", sprintf( esc_html__( 'Successfully added %1$d/%2$d terms to content stopwords!', 'relevanssi' ), intval( $s ), intval( $n ) ) );
}
} else {
// Add to stopwords.
$success = relevanssi_add_single_body_stopword( $term );
$term = stripslashes( $term );
$term = esc_html( $term );
if ( $verbose ) {
if ( $success ) {
// Translators: %s is the stopword.
printf( "<div id='message' class='updated fade'><p>%s</p></div>", sprintf( esc_html__( "Term '%s' added to content stopwords!", 'relevanssi' ), esc_html( stripslashes( $term ) ) ) );
} else {
// Translators: %s is the stopword.
printf( "<div id='message' class='updated fade'><p>%s</p></div>", sprintf( esc_html__( "Couldn't add term '%s' to content stopwords!", 'relevanssi' ), esc_html( stripslashes( $term ) ) ) );
}
}
}
return $success;
}
/**
* Adds a single stopword to the stopword table.
*
* @global object $wpdb The WP database interface.
* @global array $relevanssi_variables The global Relevanssi variables.
*
* @param string $term The term to add.
*
* @return boolean True if success, false if not.
*/
function relevanssi_add_single_body_stopword( $term ) {
if ( empty( $term ) ) {
return false;
}
$term = stripslashes( relevanssi_strtolower( $term ) );
$stopwords = relevanssi_fetch_body_stopwords();
if ( in_array( $term, $stopwords, true ) ) {
return false;
}
$stopwords[] = $term;
$success = relevanssi_update_body_stopwords( $stopwords );
if ( ! $success ) {
return false;
}
global $wpdb, $relevanssi_variables;
relevanssi_delete_term_from_all_post_content( $term );
// Remove all lines with all zeros, ie. no matches.
$wpdb->query(
'DELETE FROM '
. $relevanssi_variables['relevanssi_table'] // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
. ' WHERE content + title + comment + tag + link + author + category + excerpt + taxonomy + customfield + mysqlcolumn = 0'
);
return true;
}
/**
* Deletes a term from all posts in the database, language considered.
*
* If Polylang or WPML are used, deletes the term only from the posts matching
* the current language.
*
* @param string $term The term to delete.
*/
function relevanssi_delete_term_from_all_post_content( $term ) {
global $wpdb, $relevanssi_variables;
if ( function_exists( 'pll_languages_list' ) ) {
$term_id = relevanssi_get_language_term_taxonomy_id(
relevanssi_get_current_language()
);
$wpdb->query(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
"UPDATE {$relevanssi_variables['relevanssi_table']}
SET content = 0
WHERE term=%s
AND doc IN (
SELECT object_id
FROM $wpdb->term_relationships
WHERE term_taxonomy_id = %d
)",
$term,
$term_id
)
);
return;
}
if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
$language = relevanssi_get_current_language( false );
$wpdb->query(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
"UPDATE {$relevanssi_variables['relevanssi_table']}
SET content = 0
WHERE term=%s
AND doc IN (
SELECT DISTINCT(element_id)
FROM {$wpdb->prefix}icl_translations
WHERE language_code = %s
)",
$term,
$language
)
);
return;
}
// No language defined, just remove from the index.
$wpdb->query(
$wpdb->prepare(
'UPDATE ' . $relevanssi_variables['relevanssi_table'] . ' SET content = 0 WHERE term=%s', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$term
)
);
}
/**
* Removes all content stopwords in specific language.
*
* Empties the relevanssi_body_stopwords option for particular language.
*
* @param string $language The language code of stopwords. If empty, removes
* the stopwords for the current language.
*/
function relevanssi_remove_all_body_stopwords( $language = null ) {
if ( ! $language ) {
$language = relevanssi_get_current_language();
}
$stopwords = get_option( 'relevanssi_body_stopwords', array() );
unset( $stopwords[ $language ] );
$success = update_option( 'relevanssi_body_stopwords', $stopwords );
if ( $success ) {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__( 'All content stopwords removed! Remember to re-index.', 'relevanssi' )
);
} else {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
esc_html__( "There was a problem, and content stopwords couldn't be removed.", 'relevanssi' )
);
}
}
/**
* Updates the current language content stopwords in the stopwords option.
*
* Fetches the stopwords option, replaces the current language stopwords with
* the parameter array and updates the option.
*
* @param array $stopwords An array of stopwords.
*
* @return boolean The return value from update_option().
*/
function relevanssi_update_body_stopwords( $stopwords ) {
$current_language = relevanssi_get_current_language();
$stopwords_option = get_option( 'relevanssi_body_stopwords', array() );
$stopwords_option[ $current_language ] = implode( ',', array_filter( $stopwords ) );
return update_option(
'relevanssi_body_stopwords',
$stopwords_option
);
}
/**
* Removes a single content stopword.
*
* @param string $term The stopword to remove.
* @param boolean $verbose If true, print out a notice. Default true.
*
* @return boolean True if success, false if not.
*/
function relevanssi_remove_body_stopword( $term, $verbose = true ) {
$stopwords = relevanssi_fetch_body_stopwords();
$term = stripslashes( $term );
$stopwords = array_filter(
$stopwords,
function( $stopword ) use ( $term ) {
return $stopword !== $term;
}
);
$success = relevanssi_update_body_stopwords( $stopwords );
if ( $success ) {
if ( $verbose ) {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"Term '%s' removed from content stopwords! Re-index to get it back to index.",
'relevanssi'
),
esc_html( stripslashes( $term ) )
)
);
}
return true;
} else {
if ( $verbose ) {
printf(
"<div id='message' class='updated fade'><p>%s</p></div>",
sprintf(
// Translators: %s is the stopword.
esc_html__(
"Couldn't remove term '%s' from content stopwords!",
'relevanssi'
),
esc_html( stripslashes( $term ) )
)
);
}
return false;
}
}
/**
* Fetches the list of content stopwords.
*
* Gets the list of content stopwords from the options.
*
* @return array An array of stopwords.
*/
function relevanssi_fetch_body_stopwords() {
$current_language = relevanssi_get_current_language();
$stopwords_array = get_option( 'relevanssi_body_stopwords', array() );
$stopwords = isset( $stopwords_array[ $current_language ] ) ? $stopwords_array[ $current_language ] : '';
$stopword_list = $stopwords ? explode( ',', $stopwords ) : array();
return $stopword_list;
}
/**
* Displays a list of body stopwords.
*
* Displays the list of body stopwords and gives the controls for adding new stopwords.
*/
function relevanssi_show_body_stopwords() {
printf(
'<p>%s</p>',
esc_html__( 'Post content stopwords are like stopwords, but they are only applied to the post content. These words can be used for searching and will be found in post titles, custom fields and other indexed content just not in the post body content. Sometimes a word can be very common, but also have a more specific meaning and use on your site, and making it a content stopword will make it easier to find the specific use cases.', 'relevanssi' )
);
?>
<table class="form-table">
<tr>
<th scope="row">
<label for="addbodystopword"><p><?php esc_html_e( 'Content stopword(s) to add', 'relevanssi' ); ?>
</th>
<td>
<textarea name="addbodystopword" id="addbodystopword" rows="2" cols="80"></textarea>
<p><input type="submit" value="<?php esc_attr_e( 'Add', 'relevanssi' ); ?>" class='button' /></p>
</td>
</tr>
</table>
<p><?php esc_html_e( "Here's a list of content stopwords in the database. Click a word to remove it from content stopwords. You need to reindex the database to get the words back in to the index.", 'relevanssi' ); ?></p>
<table class="form-table">
<tr>
<th scope="row">
<?php esc_html_e( 'Current content stopwords', 'relevanssi' ); ?>
</th>
<td>
<ul>
<?php
$stopwords = array_map( 'stripslashes', relevanssi_fetch_body_stopwords() );
$exportlist = htmlspecialchars( implode( ', ', $stopwords ) );
sort( $stopwords );
array_walk(
$stopwords,
function ( $term ) {
printf( '<li style="display: inline;"><input type="submit" name="removebodystopword" value="%s"/></li>', esc_attr( $term ) );
}
);
?>
</ul>
<p><input type="submit" id="removeallbodystopwords" name="removeallbodystopwords" value="<?php esc_attr_e( 'Remove all content stopwords', 'relevanssi' ); ?>" class='button' /></p>
</td>
</tr>
<tr>
<th scope="row">
<?php esc_html_e( 'Exportable list of content stopwords', 'relevanssi' ); ?>
</th>
<td>
<label for="bodystopwords" class="screen-reader-text"><?php esc_html_e( 'Exportable list of content stopwords', 'relevanssi' ); ?></label>
<textarea name="bodystopwords" id="bodystopwords" rows="2" cols="80"><?php echo esc_textarea( $exportlist ); ?></textarea>
<p class="description"><?php esc_html_e( 'You can copy the list of content stopwords from here if you want to back up the list, copy it to a different blog or otherwise need the list.', 'relevanssi' ); ?></p>
</td>
</tr>
</table>
<?php
}
/**
* Blocks body stopwords from partial matches.
*
* If the search term is a body stopword, all cases where all the matches are
* in the post content are removed from the results by setting the match
* weight to 0. This will eliminate all partial matches based on body stopwords
* from the results.
*
* @param object $match The match object.
* @param int $idf The IDF value (not used here).
* @param string $term The original search term.
*
* @return object The match object.
*/
function relevanssi_block_body_stopwords( $match, $idf, $term ) {
$body_stopwords = relevanssi_fetch_body_stopwords();
if ( in_array( $term, $body_stopwords, true ) ) {
$sum = $match->content
+ $match->title
+ $match->comment
+ $match->link
+ $match->author
+ $match->excerpt
+ $match->customfield
+ $match->mysqlcolumn
+ $match->tag
+ $match->taxonomy
+ $match->category;
if ( (int) $match->content === (int) $sum ) {
$match->weight = 0;
}
}
return $match;
}

Some files were not shown because too many files have changed in this diff Show More