Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,343 @@
<?php
namespace WPDRMS\ASP\Search;
use stdClass;
use WPDRMS\ASP\Models\SearchQueryArgs;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
/**
* Search Abstract
*
* @phpstan-type ResultObj stdClass&object{
* id: int,
* blogid: int,
* relevance: int
* }
*
* @phpstan-type QueryParts array<int, array<int, array<string>>>
*/
abstract class AbstractSearch {
/**
* @var int Total results count (unlimited)
*/
public int $results_count = 0;
/**
* @var int Actual results count, results which are returned
*/
public int $return_count = 0;
/**
* @var SearchQueryArgs Parameters
*/
protected SearchQueryArgs $args;
protected string $pre_field = '';
protected string $suf_field = '';
protected string $pre_like = '';
protected string $suf_like = '';
/**
* @var int the remaining limit (number of items to look for)
*/
protected int $remaining_limit;
/**
* @var int the start of the limit
*/
protected int $limit_start = 0;
/**
* @var int remaining limit modifier
*/
protected int $remaining_limit_mod = 10;
/**
* @var array<string, mixed> Submitted options from the front end
*/
protected array $options;
/**
* @var ResultObj[] Results
*/
protected array $results = array();
/**
* @var string The search phrase
*/
protected string $s;
/**
* @var string[] Each search phrase
*/
protected array $_s; // @phpcs:ignore
/**
* @var string The reversed search phrase
*/
protected string $sr;
/**
* @var string[] Each reversed search phrase
*/
protected array $_sr; // @phpcs:ignore
/**
* @var int the current blog ID
*/
protected int $c_blogid;
/**
* @var string the final search query
*/
protected string $query;
/**
* @param SearchQueryArgs $args Parameters
*/
public function __construct( SearchQueryArgs $args ) {
$this->args = $args;
if ( isset($args['_remaining_limit_mod']) ) {
$this->remaining_limit_mod = $args['_remaining_limit_mod'];
}
$this->c_blogid = get_current_blog_id();
}
/**
* Initiates the search operation
*
* @param string $s Search Phrase
* @return ResultObj[]
*/
public function search( string $s = '' ): array {
if ( MB::strlen($s) > 120 ) {
$s = MB::substr($s, 0, 120);
}
$this->prepareKeywords($s);
$this->doSearch();
$this->postProcess();
return $this->results;
}
/**
* @param null|string $s Search Phrase
* @return void
*/
public function prepareKeywords( ?string $s ): void {
if ( $s !== null ) {
$keyword = $s;
} else {
$keyword = $this->args['s'];
}
// This is the "japanese" ideographic space character, replaced by the regular space
$keyword = preg_replace('@[  ]@u', ' ', $keyword);
$keyword = $this->compatibility($keyword);
$keyword_rev = Str::reverse($keyword);
$this->s = Str::escape( $keyword );
$this->sr = Str::escape( $keyword_rev );
/**
* Avoid double escape, explode the $keyword instead of $this->s
* Regex to match individual words and phrases between double quotes
*/
if (
preg_match_all( '/«.*?»/', $keyword, $m ) > 0 && // Only if there is at lease one complete «text» match
preg_match_all( '/«.*?(»|$)|((?<=[\t «,+])|^)[^\t »,+]+/', $keyword, $matches )
) {
$this->_s = $this->parseSearchTerms( $matches[0] );
} elseif (
preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $keyword, $matches )
) {
$this->_s = $this->parseSearchTerms( $matches[0] );
} else {
$this->_s = $this->parseSearchTerms( explode(' ', $keyword) );
}
if (
preg_match_all( '/«.*?»/', $keyword_rev, $m ) > 0 && // Only if there is at lease one complete «text» match
preg_match_all( '/«.*?(»|$)|((?<=[\t «,+])|^)[^\t »,+]+/', $keyword_rev, $matches )
) {
$this->_sr = $this->parseSearchTerms( array_reverse($matches[0]) );
} elseif ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $keyword_rev, $matches ) ) {
$this->_sr = $this->parseSearchTerms( array_reverse($matches[0]) );
} else {
$this->_sr = $this->parseSearchTerms( array_reverse( explode(' ', $keyword_rev ) ) );
}
foreach ( $this->_s as $k =>$w ) {
if ( MB::strlen($w) < $this->args['min_word_length'] ) {
unset($this->_s[ $k ]);
}
}
foreach ( $this->_sr as $k =>$w ) {
if ( MB::strlen($w) < $this->args['min_word_length'] ) {
unset($this->_sr[ $k ]);
}
}
/**
* Reindex the arrays, in case there are missing keys from the previous removals
*/
if ( count($this->_s) > 0 ) {
$this->_s = array_values($this->_s);
$this->_sr = array_values($this->_sr);
}
}
/**
* Check if the terms are suitable for searching.
*
* @param string[] $terms Terms to check.
* @return string[] Terms
*/
protected function parseSearchTerms( array $terms ): array {
$checked = array();
foreach ( $terms as $term ) {
// keep before/after spaces when term is for exact match
if ( preg_match( '/^".+"$/', $term ) ) {
$term = trim($term, "\"'");
} elseif ( preg_match( '/^«.+»$/', $term ) ) { // same for russian quotes
$term = trim($term, "«»'");
} else {
$term = trim($term, "\"' ");
}
if ( $term !== '' ) {
$checked[] = $term;
}
}
if ( count($checked) > 0 ) {
$checked = Str::escape(
array_slice(array_unique($checked), 0, $this->args['_keyword_count_limit'])
);
}
return $checked;
}
/**
* The search function
*/
abstract protected function doSearch(): void;
/**
* Post-processing abstract
*/
protected function postProcess(): void {}
/**
* Converts the keyword to the correct case and sets up the pre-suff fields.
*
* @param string $s
* @return string
*/
protected function compatibility( string $s ): string {
/**
* On forced case sensitivity: Let's add BINARY keyword before the LIKE
* On forced case in-sensitivity: Append the lower() function around each field
*/
if ( $this->args['_db_force_case'] === 'sensitivity' ) {
$this->pre_like = 'BINARY ';
} elseif ( $this->args['_db_force_case'] === 'insensitivity' ) {
if ( function_exists( 'mb_convert_case' ) ) {
$s = mb_convert_case( $s, MB_CASE_LOWER, 'UTF-8' );
} else {
$s = strtoupper( $s );
}
// if no mb_ functions :(
$this->pre_field .= 'lower(';
$this->suf_field .= ')';
}
/**
* Check if utf8 is forced on LIKE
*/
if ( $this->args['_db_force_utf8_like'] ) {
$this->pre_like .= '_utf8';
}
/**
* Check if unicode is forced on LIKE, but only apply if utf8 is not
*/
if ( $this->args['_db_force_unicode'] && !$this->args['_db_force_utf8_like'] ) {
$this->pre_like .= 'N';
}
return $s;
}
/**
* Builds the query from the parts
*
* @param QueryParts $parts
*
* @return string query
*/
protected function buildQuery( array $parts ): string {
$args = &$this->args;
$kw_logic = str_replace('ex', '', $args['keyword_logic'] );
$kw_logic = $kw_logic !== 'and' && $kw_logic !== 'or' ? 'and' : $kw_logic;
$r_parts = array(); // relevance parts
/*------------------------- Build like --------------------------*/
$exact_query = '';
$like_query_arr = array();
foreach ( $parts as $k =>$part ) {
if ( $k === 0 ) {
$exact_query = '(' . implode(' OR ', $part[0]) . ')';
} else {
$like_query_arr[] = '(' . implode(' OR ', $part[0]) . ')';
}
}
$like_query = implode(' ' . strtoupper($kw_logic) . ' ', $like_query_arr);
// When $exact query is empty, then surely $like_query must be empty too, see above
if ( $exact_query === '' ) {
$like_query = '(1)';
} elseif ( $like_query !== '' ) {
$like_query = "( $exact_query OR $like_query )";
} else {
$like_query = "( $exact_query )";
}
/*---------------------------------------------------------------*/
/*---------------------- Build relevance ------------------------*/
foreach ( $parts as $part ) {
if ( isset($part[1]) && count($part[1]) > 0 ) {
$r_parts = array_merge( $r_parts, $part[1] );
}
}
$relevance = implode( ' + ', $r_parts );
if ( !$args['_post_use_relevance'] || $relevance === '' ) {
$relevance = '(1)';
} else {
$relevance = "($relevance)";
}
/*---------------------------------------------------------------*/
if ( isset($this->remaining_limit) ) {
if ( $this->limit_start !== 0 ) {
$limit = $this->limit_start . ', ' . $this->remaining_limit;
} else {
$limit = $this->remaining_limit;
}
} else {
$limit = 10;
}
return str_replace(
array( '{relevance_query}', '{like_query}', '{remaining_limit}' ),
array( $relevance, $like_query, $limit ),
$this->query
);
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\WPMU;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchBlogs extends AbstractSearch {
protected function doSearch(): void {
$args = &$this->args;
$sd = $args['_sd'] ?? array();
/* There are no blog images available, return nothing for polaroid mode */
if ( $args['_ajax_search'] && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
return;
}
$s = $this->s;
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['blogs_limit'];
} else {
$limit = $args['blogs_limit_override'];
}
if ( $limit <= 0 ) {
return;
}
$blogresults = array();
$blog_list = WPMU::getBlogList();
foreach ( $blog_list as $bk => $blog ) {
if ( in_array($blog['blog_id'], $args['blog_exclude']) ) { // @phpcs:ignore
unset($blog_list[ $bk ]);
}
$_det = get_blog_details($blog['blog_id']);
if ( $_det === false ) {
unset($blog_list[ $bk ]);
continue;
}
$blog_list[ $bk ]['name'] = $_det->blogname;
$blog_list[ $bk ]['siteurl'] = $_det->siteurl;
$blog_list[ $bk ]['match'] = 0;
}
foreach ( $blog_list as $bk => $blog ) {
$pos = strpos(strtolower($blog['name']), $s);
if ( $pos !== false ) {
$blog_list[ $bk ]['match'] = 1;
}
}
foreach ( $blog_list as $blog ) {
if ( $blog['match'] ) {
switch_to_blog($blog['blog_id']);
$blogresults[] = (object) array(
'title' => $blog['name'],
'link' => get_bloginfo('url'),
'content' => get_bloginfo('description'),
'author' => '',
'date' => '',
'content_type' => 'blog',
'g_content_type' => 'blogs',
'blogid' => $blog['blog_id'],
'id' => $blog['blog_id'],
'relevance' => 1,
);
restore_current_blog();
}
}
if ( $sd['blogtitleorderby'] === 'asc' ) {
$blogresults = array_reverse($blogresults);
}
$this->results_count = count($blogresults);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$blogresults = array_slice($blogresults, $args['_call_num'] * $limit, $limit);
$this->results = $blogresults;
$this->return_count = count($this->results);
}
protected function postProcess(): void {}
}

View File

@@ -0,0 +1,472 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Str;
use WPDRMS\ASP\Utils\Post;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchBuddyPress extends AbstractSearch {
/**
* @noinspection PhpUndefinedClassInspection
* @noinspection PhpUndefinedFunctionInspection
* @noinspection DuplicatedCode
*/
protected function doSearch(): void {
global $wpdb;
global $q_config;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
$kw_logic = $args['keyword_logic'];
$q_config['language'] = $args['_qtranslate_lang'];
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['buddypress_limit'];
} else {
$limit = $args['buddypress_limit_override'];
}
if ( $limit <= 0 ) {
return;
}
$replies_results = array();
$group_results = array();
$activity_results = array();
$words = $args['_exact_matches'] ? array( $s ) : $_s;
if (
strpos($args['post_primary_order'], 'customfp') !== false ||
strpos($args['post_primary_order'], 'menu_order') !== false
) {
$orderby_primary = 'relevance DESC';
} else {
$orderby_primary = str_replace('post_', '', $args['post_primary_order']);
}
if (
strpos($args['post_secondary_order'], 'customfs') !== false ||
strpos($args['post_secondary_order'], 'menu_order') !== false
) {
$orderby_secondary = 'date DESC';
} else {
$orderby_secondary = str_replace('post_', '', $args['post_secondary_order']);
}
if (
!function_exists('bp_is_active') ||
!function_exists('bp_core_get_user_domain') ||
!function_exists('bp_core_fetch_avatar') ||
!function_exists('bp_get_group_url')
) {
return;
}
/*----------------------- Groups query --------------------------*/
if ( $args['bp_groups_search'] && bp_is_active('groups') && class_exists('\\BP_Groups_Group') ) {
$parts = array();
$relevance_parts = array();
/*------------------------- Statuses ----------------------------*/
$statuses = array();
if ( $args['bp_groups_search_public'] ) {
$statuses[] = 'public';
}
if ( $args['bp_groups_search_private'] ) {
$statuses[] = 'private';
}
if ( $args['bp_groups_search_hidden'] ) {
$statuses[] = 'hidden';
}
if ( count($statuses) < 1 ) {
return;
}
$swords = implode("','", $statuses);
$group_statuses = '( ' . $wpdb->prefix . "bp_groups.status IN ('$swords') )";
/*---------------------------------------------------------------*/
if ( $s !== '' ) {
/*------------------------- Title query -------------------------*/
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$op = strtoupper($kw_logic);
if ( count($_s) > 0 ) {
$_like = implode("%' " . $op . ' ' . $wpdb->prefix . "bp_groups.name LIKE '%", $words);
} else {
$_like = $s;
}
$parts[] = '( ' . $wpdb->prefix . "bp_groups.name LIKE '$wcl" . $_like . "$wcr' )";
} else {
$_like = array();
$op = $kw_logic === 'andex' ? 'AND' : 'OR';
foreach ( $words as $word ) {
$_like[] = '
( ' . $wpdb->prefix . "bp_groups.name LIKE '% " . $word . " %'
OR " . $wpdb->prefix . "bp_groups.name LIKE '" . $word . " %'
OR " . $wpdb->prefix . "bp_groups.name LIKE '% " . $word . "'
OR " . $wpdb->prefix . "bp_groups.name = '" . $word . "')";
}
$parts[] = '(' . implode(' ' . $op . ' ', $_like) . ')';
}
if ( count($_s) > 0 ) {
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_groups.name LIKE '%$_s[0]%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_groups.name LIKE '%$s%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
/*---------------------------------------------------------------*/
/*---------------------- Description query ----------------------*/
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$op = strtoupper($kw_logic);
if ( count($_s) > 0 ) {
$_like = implode("%' " . $op . ' lower(' . $wpdb->prefix . "bp_groups.description) LIKE '%", $words);
} else {
$_like = $s;
}
$parts[] = '( lower(' . $wpdb->prefix . "bp_groups.description) LIKE '$wcl" . $_like . "$wcr' )";
} else {
$_like = array();
$op = $kw_logic === 'andex' ? 'AND' : 'OR';
foreach ( $words as $word ) {
$_like[] = '
(lower(' . $wpdb->prefix . "bp_groups.description) LIKE '% " . $word . " %'
OR lower(" . $wpdb->prefix . "bp_groups.description) LIKE '" . $word . " %'
OR lower(" . $wpdb->prefix . "bp_groups.description) LIKE '% " . $word . "'
OR lower(" . $wpdb->prefix . "bp_groups.description) = '" . $word . "')";
}
$parts[] = '(' . implode(' ' . $op . ' ', $_like) . ')';
}
if ( count($_s) > 0 ) {
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_groups.description LIKE '%$_s[0]%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_groups.description LIKE '%$s%')
then " . w_isset_def($sd['econtentweight'], 10) . ' else 0 end)';
/*---------------------------------------------------------------*/
}
/*------------------------- Build like --------------------------*/
$like_query = implode(' OR ', $parts);
if ( $like_query === '' ) {
$like_query = '(1)';
} else {
$like_query = "($like_query)";
}
/*---------------------------------------------------------------*/
/*---------------------- Build relevance ------------------------*/
$relevance = implode(' + ', $relevance_parts);
if ( !$args['_post_use_relevance'] || $relevance === '' ) {
$relevance = '(1)';
} else {
$relevance = "($relevance)";
}
/*---------------------------------------------------------------*/
$querystr = '
SELECT
{args_fields}
' . $wpdb->prefix . "bp_groups.id as id,
$this->c_blogid as `blogid`,
" . $wpdb->prefix . 'bp_groups.name as `title`,
' . $wpdb->prefix . 'bp_groups.description as `content`,
' . $wpdb->prefix . "bp_groups.date_created as `date`,
$wpdb->users.user_nicename as `author`,
'bp_group' as `content_type`,
'bp_groups' as `g_content_type`,
$relevance as `relevance`
FROM
" . $wpdb->prefix . "bp_groups
LEFT JOIN $wpdb->users ON $wpdb->users.ID = " . $wpdb->prefix . "bp_groups.creator_id
{args_join}
WHERE
$group_statuses
{args_where}
AND $like_query
GROUP BY {args_groupby}
ORDER BY {args_orderby} $orderby_primary, $orderby_secondary
LIMIT " . $limit;
// Place the argument query fields
if ( isset($args['buddypress_groups_query']) && is_array($args['buddypress_groups_query']) ) {
$querystr = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array(
$args['buddypress_groups_query']['fields'],
$args['buddypress_groups_query']['join'],
$args['buddypress_groups_query']['where'],
$args['buddypress_groups_query']['orderby'],
),
$querystr
);
} else {
$querystr = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$querystr
);
}
if ( isset($args['buddypress_groups_query']['groupby']) && $args['buddypress_groups_query']['groupby'] !== '' ) {
$querystr = str_replace('{args_groupby}', $args['buddypress_groups_query']['groupby'], $querystr);
} else {
$querystr = str_replace('{args_groupby}', $wpdb->prefix . 'bp_groups.id', $querystr);
}
$group_results = $wpdb->get_results($querystr); // @phpcs:ignore
if ( isset($sd['image_options']) ) {
foreach ( $group_results as $k => &$v ) {
/* @noinspection All */
$group = new \BP_Groups_Group($v->id); // @phpstan-ignore
$v->link = bp_get_group_url($group);
if ( $sd['image_options']['show_images'] ) {
$avatar_options = array(
'item_id' => $v->id,
'object' => 'group',
'type' => 'full',
'html' => false,
);
$im = bp_core_fetch_avatar($avatar_options);
if ( $im !== '' ) {
$v->image = Str::fixSSLURLs($im);
}
}
/* Remove the results in polaroid mode */
if ( $args['_ajax_search'] && empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
unset($group_results[ $k ]);
continue;
}
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = $_content;
// --------------------------------- DATE -----------------------------------
if ( $sd['showdate'] ) {
$post_time = strtotime($v->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$v->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
}
/*---------------------------------------------------------------*/
/*----------------------- Activity query ------------------------*/
if ( $args['bp_activities_search'] && bp_is_active('activity') ) {
if ( !function_exists('bp_activity_get_permalink') ) {
return;
}
$parts = array();
$relevance_parts = array();
/*---------------------- Description query ----------------------*/
if ( $s !== '' ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$op = strtoupper($kw_logic);
if ( count($_s) > 0 ) {
$_like = implode("%' " . $op . ' lower(' . $wpdb->prefix . "bp_activity.content) LIKE '%", $words);
} else {
$_like = $s;
}
$parts[] = '( ' . $wpdb->prefix . "bp_activity.content LIKE '$wcl" . $_like . "$wcr' )";
} else {
$_like = array();
$op = $kw_logic === 'andex' ? 'AND' : 'OR';
foreach ( $words as $word ) {
$_like[] = '
( ' . $wpdb->prefix . "bp_activity.content LIKE '% " . $word . " %'
OR " . $wpdb->prefix . "bp_activity.content LIKE '" . $word . " %'
OR " . $wpdb->prefix . "bp_activity.content LIKE '% " . $word . "'
OR " . $wpdb->prefix . "bp_activity.content = '" . $word . "')";
}
$parts[] = '(' . implode(' ' . $op . ' ', $_like) . ')';
}
if ( count($_s) > 0 ) {
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_activity.content LIKE '%$_s[0]%')
then " . w_isset_def($sd['econtentweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
( ' . $wpdb->prefix . "bp_activity.content LIKE '%$s%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
/*---------------------------------------------------------------*/
/*------------------------- Build like --------------------------*/
$like_query = implode(' OR ', $parts);
if ( $like_query === '' ) {
$like_query = '(1)';
} else {
$like_query = "($like_query)";
}
/*---------------------------------------------------------------*/
/*---------------------- Build relevance ------------------------*/
$relevance = implode(' + ', $relevance_parts);
if ( !$args['_post_use_relevance'] || $relevance === '' ) {
$relevance = '(1)';
} else {
$relevance = "($relevance)";
}
/*---------------------------------------------------------------*/
$querystr = '
SELECT
{args_fields}
' . $wpdb->prefix . "bp_activity.id as id,
$this->c_blogid as `blogid`,
$wpdb->users.display_name as `title`,
" . $wpdb->prefix . 'bp_activity.content as `content`,
' . $wpdb->prefix . "bp_activity.date_recorded as `date`,
$wpdb->users.display_name as `author`,
" . $wpdb->prefix . "bp_activity.user_id as author_id,
'bp_activity' as `content_type`,
'bp_activities' as `g_content_type`,
$relevance as `relevance`
FROM
" . $wpdb->prefix . "bp_activity
LEFT JOIN $wpdb->users ON $wpdb->users.ID = " . $wpdb->prefix . 'bp_activity.user_id
{args_join}
WHERE
' . $wpdb->prefix . "bp_activity.component IN ('activity', 'groups')
AND " . $wpdb->prefix . 'bp_activity.is_spam = 0
AND ' . $wpdb->prefix . "bp_activity.hide_sitewide = 0
AND $like_query
{args_where}
GROUP BY {args_groupby}
ORDER BY {args_orderby} $orderby_primary, $orderby_secondary
LIMIT " . $limit;
// Place the argument query fields
if ( isset($args['buddypress_activities_query']) && is_array($args['buddypress_activities_query']) ) {
$querystr = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array(
$args['buddypress_activities_query']['fields'],
$args['buddypress_activities_query']['join'],
$args['buddypress_activities_query']['where'],
$args['buddypress_activities_query']['orderby'],
),
$querystr
);
} else {
$querystr = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$querystr
);
}
if ( isset($args['buddypress_activities_query']['groupby']) && $args['buddypress_activities_query']['groupby'] !== '' ) {
$querystr = str_replace('{args_groupby}', $args['buddypress_activities_query']['groupby'], $querystr);
} else {
$querystr = str_replace('{args_groupby}', $wpdb->prefix . 'bp_activity.id', $querystr);
}
$activity_results = $wpdb->get_results($querystr); // phpcs:ignore
foreach ( $activity_results as $k => &$v ) {
$v->link = bp_activity_get_permalink($v->id);
$v->image = Str::fixSSLURLs(
bp_core_fetch_avatar(
array(
'item_id' => $v->author_id,
'html' => false,
)
)
);
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = $_content;
// --------------------------------- DATE -----------------------------------
if ( isset($sd['showdate']) && $sd['showdate'] ) {
$post_time = strtotime($v->date);
/* Remove the results in polaroid mode */
if ( $args['_ajax_search'] && empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
unset($activity_results[ $k ]);
continue;
}
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$v->date = @date_i18n($date_format, $post_time); // phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
do_action('bbpress_init');
$this->results_count = count($group_results) + count($activity_results);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$this->results = array(
'repliesresults' => $replies_results,
'groupresults' => $group_results,
'activityresults' => $activity_results,
);
$this->return_count = count($group_results) + count($activity_results);
}
protected function postProcess(): void {}
}

View File

@@ -0,0 +1,267 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchComments extends SearchPostTypes {
/** @noinspection DuplicatedCode */
protected function doSearch(): void {
global $wpdb;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
$s = $this->s;
$_s = $this->_s;
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['comments_limit'];
} else {
$limit = $args['comments_limit_override'];
}
$query_limit = $limit * 3;
if ( $limit <= 0 ) {
return;
}
// Prefixes and suffixes
$pre_field = '';
$suf_field = '';
$pre_like = '';
$suf_like = '';
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
$kw_logic = $args['keyword_logic'];
// ------------------------ Categories/taxonomies ----------------------
$term_query = $this->buildTermQuery( $wpdb->comments . '.comment_post_ID', 'comment_post_type' );
// ---------------------------------------------------------------------
/*------------- Custom Fields with Custom selectors -------------*/
$cf_select = $this->buildCffQuery( $wpdb->comments . '.comment_post_ID' );
/*---------------------------------------------------------------*/
/*----------------------- Date filtering ------------------------*/
$date_query = '';
$date_query_parts = $this->get_date_query_parts( $wpdb->comments, 'comment_date' );
if ( count($date_query_parts) > 0 ) {
$date_query = ' AND (' . implode(' AND ', $date_query_parts) . ') ';
}
/*---------------------------------------------------------------*/
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
/*---------------------- Content query --------------------------*/
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added && isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->comments . '.comment_content' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
/*---------------------------------------------------------------*/
$this->parts[] = array( $parts, $relevance_parts );
$relevance_added = true;
}
/*------------------------ Exclude ids --------------------------*/
if ( !empty($args['post_not_in']) ) {
$exclude_posts = "AND ($wpdb->comments.comment_post_ID NOT IN (" . ( is_array($args['post_not_in']) ? implode(',', $args['post_not_in']) : $args['post_not_in'] ) . '))';
} else {
$exclude_posts = '';
}
if ( !empty($args['post_not_in2']) ) {
$exclude_posts .= "AND ($wpdb->comments.comment_post_ID NOT IN (" . implode(',', $args['post_not_in2']) . '))';
}
/*---------------------------------------------------------------*/
/*------------------------ Include ids --------------------------*/
if ( !empty($args['post_in']) ) {
$include_posts = "AND ($wpdb->comments.comment_post_ID IN (" . ( is_array($args['post_in']) ? implode(',', $args['post_in']) : $args['post_in'] ) . '))';
} else {
$include_posts = '';
}
/*---------------------------------------------------------------*/
/*----------------------- Exclude USER id -----------------------*/
$user_query = '';
if ( isset($args['post_user_filter']['include']) ) {
if ( !in_array(-1, $args['post_user_filter']['include']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->comments.user_id IN (" . implode(', ', $args['post_user_filter']['include']) . ')
';
}
}
if ( isset($args['post_user_filter']['exclude']) ) {
if ( !in_array(-1, $args['post_user_filter']['exclude']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->comments.user_id NOT IN (" . implode(', ', $args['post_user_filter']['exclude']) . ') ';
} else {
return;
}
}
/*---------------------------------------------------------------*/
if (
strpos($args['post_primary_order'], 'customfp') !== false ||
strpos($args['post_primary_order'], 'menu_order') !== false
) {
$orderby_primary = 'relevance DESC';
} else {
$orderby_primary = str_replace('post_', '', $args['post_primary_order']);
}
if (
strpos($args['post_secondary_order'], 'customfs') !== false ||
strpos($args['post_secondary_order'], 'menu_order') !== false
) {
$orderby_secondary = 'date DESC';
} else {
$orderby_secondary = str_replace('post_', '', $args['post_secondary_order']);
}
$this->query = "
SELECT
$wpdb->comments.comment_ID as id,
$this->c_blogid as `blogid`,
$wpdb->comments.comment_post_ID as post_id,
'post' as comment_post_type,
$wpdb->comments.user_id as user_id,
$wpdb->comments.comment_content as `title`,
$wpdb->comments.comment_content as `content`,
'comment' as `content_type`,
'comments' as `g_content_type`,
$wpdb->comments.comment_date as `date`,
$wpdb->comments.user_id as user_id,
{relevance_query} as `relevance`
FROM $wpdb->comments
WHERE
($wpdb->comments.comment_approved=1)
$term_query
AND $cf_select
$date_query
$user_query
AND {like_query}
$exclude_posts
$include_posts
ORDER BY $orderby_primary, $orderby_secondary
LIMIT " . $query_limit;
$querystr = $this->buildQuery( $this->parts );
$querystr = apply_filters('asp_query_comments', $querystr, $args, $args['_id'], $args['_ajax_search']);
$comment_results = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($comment_results);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$comment_results = array_slice($comment_results, $args['_call_num'] * $limit, $limit);
$this->results = &$comment_results;
$this->return_count = count($this->results);
}
/** @noinspection DuplicatedCode */
protected function postProcess(): void {
$r = &$this->results;
$args = $this->args;
$s = $this->s;
$_s = $this->_s;
$sd = $args['_sd'];
foreach ( $r as $k => $v ) {
$v->link = get_comment_link($v->id);
$v->author = get_comment_author($v->id);
if ( MB::strlen($v->content) > 40 ) {
$v->title = wd_substr_at_word($v->content, 40);
} else {
$v->title = $v->content;
}
if ( $sd['showdescription'] ) {
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = Str::fixSSLURLs( wd_closetags($_content) );
} else {
$v->content = '';
}
/* Remove the results in polaroid mode */
if ( $args['_ajax_search'] && empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
unset($this->results[ $k ]);
continue;
}
// --------------------------------- DATE -----------------------------------
if ( isset($sd['showdate']) && $sd['showdate'] ) {
$post_time = strtotime($v->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$v->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
}

View File

@@ -0,0 +1,828 @@
<?php
/** @noinspection RegExpRedundantEscape */
namespace WPDRMS\ASP\Search;
use stdClass;
use WP_Post;
use WPDRMS\ASP\Misc\Priorities;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
/**
* Index Type Search
*
* @phpstan-import-type ResultObj from AbstractSearch
*/
class SearchIndex extends SearchPostTypes {
/**
* @var ResultObj[] results from the index table
*/
protected array $raw_results = array();
protected function doSearch(): void {
global $wpdb;
global $q_config;
$current_blog_id = get_current_blog_id();
$args = &$this->args;
// Check if there is anything left to look for
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['posts_limit'];
} else {
$limit = $args['posts_limit_override'];
}
if ( $limit <= 0 ) {
return;
}
$sd = $args['_sd'] ?? array();
$kw_logic = $args['keyword_logic'];
$q_config['language'] = $args['_qtranslate_lang'];
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
$sr = $this->sr; // full reversed keyword
$_sr = $this->_sr; // array of reversed keywords
$group_priority_select = $this->buildPgpQuery('asp_index.doc');
$group_priority_select = $group_priority_select . ' AS group_priority,';
/**
* Determine if the priorities table should be used or not.
*/
$priority_select = Priorities::count() > 0 ? '
IFNULL((
SELECT
aspp.priority
FROM ' . wd_asp()->db->table('priorities') . ' as aspp
WHERE aspp.post_id = asp_index.doc AND aspp.blog_id = ' . get_current_blog_id() . '
), 100)
' : 100;
// ------------------------- Statuses ----------------------------//
// Removed - it is already considered at index generation
// ---------------------------------------------------------------//
// ----------------------- Gather Types --------------------------*/
/**
* @TODO: Cross-check with selected custom post types on the index table options panel, as if they match,
* this query is not needed at all!
*/
$page_q = '';
if ( !empty($args['_exclude_page_parent_child']) ) {
$page_q = " AND ( IF(asp_index.post_type <> 'page', 1,
EXISTS (
SELECT ID FROM $wpdb->posts xxp WHERE
xxp.ID = asp_index.doc AND
xxp.post_parent NOT IN (" . implode( ',', $args['_exclude_page_parent_child']) . ') AND
xxp.ID NOT IN (' . implode(',', $args['_exclude_page_parent_child']) . ')
)
)
)';
}
// If no post types selected, well then return
if ( count($args['post_type']) < 1 && $page_q === '' ) {
return;
} else {
$words = implode("','", $args['post_type']);
$post_types = "(asp_index.post_type IN ('$words') $page_q)";
}
/*---------------------------------------------------------------*/
$post_fields_query = '';
if ( !in_array('attachment', $args['post_type'], true) ) {
$exc_fields = array_diff(array( 'title', 'content', 'excerpt' ), $args['post_fields']);
if ( count($exc_fields) > 0 ) {
$post_fields_arr = array_map(
function ( $field ) {
return "asp_index.$field = 0";
},
$exc_fields
);
$post_fields_query = 'AND (' . implode(' AND ', $post_fields_arr) . ') ';
}
}
// ------------------------ Categories/tags/taxonomies ----------------------
$term_query = $this->buildTermQuery('asp_index.doc', 'asp_index.post_type');
// ---------------------------------------------------------------------
/*------------- Custom Fields with Custom selectors -------------*/
if (
count($args['post_type']) === 1 &&
in_array('attachment', $args['post_type'], true) &&
!$args['attachments_cf_filters']
) {
$cf_select = '(1)';
} else {
$cf_select = $this->buildCffQuery('asp_index.doc');
}
/*---------------------------------------------------------------*/
/*------------------------ Include id's -------------------------*/
if ( !empty($args['post_in']) ) {
$include_posts = ' AND (asp_index.doc IN (' . ( is_array($args['post_in']) ? implode(',', $args['post_in']) : $args['post_in'] ) . '))';
} else {
$include_posts = '';
}
/*---------------------------------------------------------------*/
/*------------------------ Exclude id's -------------------------*/
if ( !empty($args['post_not_in']) ) {
$exclude_posts = ' AND (asp_index.doc NOT IN (' . ( is_array($args['post_not_in']) ? implode(',', $args['post_not_in']) : $args['post_not_in'] ) . '))';
} else {
$exclude_posts = '';
}
if ( !empty($args['post_not_in2']) ) {
$exclude_posts .= 'AND (asp_index.doc NOT IN (' . implode(',', $args['post_not_in2']) . '))';
}
/*---------------------------------------------------------------*/
// ------------------------ Term JOIN --------------------------- //
// No need, this should be indexed...
// -------------------------------------------------------------- //
/*------------------------- WPML filter -------------------------*/
$wpml_query = '';
if ( $args['_wpml_lang'] !== '' ) {
global $sitepress;
$site_lang_selected = false;
if ( is_object($sitepress) && method_exists($sitepress, 'get_default_language') ) {
$site_lang_selected = $sitepress->get_default_language() === $args['_wpml_lang'];
}
$wpml_query = "asp_index.lang = '" . Str::escape($args['_wpml_lang']) . "'";
/**
* Imported or some custom post types might have missing translations for the site default language.
* If the user currently searches on the default language, empty translation string is allowed.
*/
if ( $args['_wpml_allow_missing_translations'] && $site_lang_selected ) {
$wpml_query .= " OR asp_index.lang = ''";
}
$wpml_query = ' AND (' . $wpml_query . ')';
}
/*---------------------------------------------------------------*/
/*----------------------- POLYLANG filter -----------------------*/
$polylang_query = '';
if ( $args['_polylang_lang'] !== '' && $wpml_query === '' ) {
$polylang_query = " AND (asp_index.lang = '" . Str::escape($args['_polylang_lang']) . "')";
}
/*---------------------------------------------------------------*/
/*----------------------- Date filtering ------------------------*/
$date_query = '';
$date_query_parts = $this->get_date_query_parts('ddpp');
if ( count($date_query_parts) > 0 ) {
$date_query = " AND EXISTS( SELECT 1 FROM $wpdb->posts as ddpp WHERE " . implode(' AND ', $date_query_parts) . ' AND ddpp.ID = asp_index.doc) ';
}
/*---------------------------------------------------------------*/
/*---------------------- Blog switching? ------------------------*/
$blog_query = '';
if ( is_multisite() ) {
if ( $args['_switch_on_preprocess'] ) {
$blog_query = 'AND asp_index.blogid IN (' . implode(',', $args['_selected_blogs']) . ')';
} else {
$blog_query = 'AND asp_index.blogid = ' . $current_blog_id;
}
}
/*---------------------------------------------------------------*/
/*---------------------- Relevance Stored -----------------------*/
$rel_val_title = $sd['it_title_weight'] ?? 10;
$rel_val_content = $sd['it_content_weight'] ?? 8;
$rel_val_excerpt = $sd['it_excerpt_weight'] ?? 5;
$rel_val_permalinks = $sd['it_terms_weight'] ?? 3;
$rel_val_terms = $sd['it_terms_weight'] ?? 3;
$rel_val_cf = $sd['it_cf_weight'] ?? 3;
$rel_val_author = $sd['it_author_weight'] ?? 2;
/*---------------------------------------------------------------*/
/*------------------- Post type based ordering ------------------*/
$p_type_priority = '';
if ( isset($sd['use_post_type_order']) && $sd['use_post_type_order'] === 1 ) {
foreach ( $sd['post_type_order'] as $pk => $p_order ) {
$p_type_priority .= "
WHEN '$p_order' THEN $pk ";
}
if ( $p_type_priority !== '' ) {
$p_type_priority = '
CASE asp_index.post_type
' . ' ' . $p_type_priority . '
ELSE 999
END ';
} else {
$p_type_priority = '1';
}
} else {
$p_type_priority = '1';
}
/*---------------------------------------------------------------*/
/*---------------- Primary custom field ordering ----------------*/
$custom_field_selectp = '1 ';
if (
strpos($args['post_primary_order'], 'customfp') !== false &&
$args['_post_primary_order_metakey'] !== ''
) {
// @phpstan-ignore-next-line
$custom_field_selectp = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->postmeta
WHERE
$wpdb->postmeta.meta_key='" . esc_sql($args['_post_primary_order_metakey']) . "' AND
$wpdb->postmeta.post_id=asp_index.doc
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
/*--------------- Secondary custom field ordering ---------------*/
$custom_field_selects = '1 ';
if (
strpos($args['post_secondary_order'], 'customfs') !== false &&
$args['_post_secondary_order_metakey'] !== ''
) {
// @phpstan-ignore-next-line
$custom_field_selects = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->postmeta
WHERE
$wpdb->postmeta.meta_key='" . esc_sql($args['_post_secondary_order_metakey']) . "' AND
$wpdb->postmeta.post_id=asp_index.doc
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
/*--------------------- Post parent IDs -------------------------*/
$post_parents_select = '';
if ( count($args['post_parent']) > 0 ) {
$post_parents_select = "AND EXISTS (
SELECT 1 FROM $wpdb->posts
WHERE
$wpdb->posts.ID = asp_index.doc AND
$wpdb->posts.post_parent IN (" . implode(',', $args['post_parent']) . ')
) ';
}
/*---------------------------------------------------------------*/
/*--------------------- Post parent IDs -------------------------*/
$post_parents_exclude_select = '';
if ( count($args['post_parent_exclude']) > 0 ) {
$post_parents_exclude_select = "AND NOT EXISTS (
SELECT 1 FROM $wpdb->posts
WHERE
$wpdb->posts.ID = asp_index.doc AND
$wpdb->posts.post_parent IN (" . implode(',', $args['post_parent_exclude']) . ')
) ';
}
/*---------------------------------------------------------------*/
/*----------------------- Exclude USER id -----------------------*/
$user_select = '0';
$user_join = '';
$user_query = '';
if ( isset($args['post_user_filter']['include']) ) {
if ( !in_array(-1, $args['post_user_filter']['include']) ) { // @phpcs:ignore
$user_query = 'AND pj.post_author IN (' . implode(', ', $args['post_user_filter']['include']) . ')
';
}
}
if ( isset($args['post_user_filter']['exclude']) ) {
if ( !in_array(-1, $args['post_user_filter']['exclude']) ) { // @phpcs:ignore
$user_query = 'AND pj.post_author NOT IN (' . implode(', ', $args['post_user_filter']['exclude']) . ') ';
} else {
return;
}
}
if ( $user_query !== '' ) {
$user_select = 'pj.post_author';
$user_join = "LEFT JOIN $wpdb->posts pj ON pj.ID = asp_index.doc";
}
/*---------------------------------------------------------------*/
/*-------------- Additional Query parts by Filters --------------*/
/**
* Use these filters to add additional parts to the select, join or where
* parts of the search query.
*/
$add_select = apply_filters('asp_it_query_add_select', '', $args, $s, $_s);
$add_join = apply_filters('asp_it_query_add_join', '', $args, $s, $_s);
$add_where = apply_filters('asp_it_query_add_where', '', $args, $s, $_s);
/*---------------------------------------------------------------*/
/**
* This is the main query.
*
* The ttid field is a bit tricky as the term_taxonomy_id doesn't always equal term_id,
* so we need the LEFT JOINS :(
*/
$this->ordering['primary'] = $args['post_primary_order'];
$this->ordering['secondary'] = $args['post_secondary_order'];
$_primary_field = explode(' ', $this->ordering['primary']);
$this->ordering['primary_field'] = $_primary_field[0];
$this->query = "
SELECT
{args_fields}
$add_select
asp_index.doc as id,
asp_index.blogid as `blogid`,
'pagepost' as `content_type`,
$priority_select as `priority`,
$p_type_priority as `p_type_priority`,
$user_select as `post_author`,
$custom_field_selectp as `customfp`,
$custom_field_selects as `customfs`,
'' as `post_date`,
'' as post_modified,
'' as `date`,
0 as menu_order,
'' as `title`,
asp_index.post_type as `post_type`,
$group_priority_select
(
asp_index.title * $rel_val_title * {rmod} +
asp_index.content * $rel_val_content * {rmod} +
asp_index.excerpt * $rel_val_excerpt * {rmod} +
asp_index.comment * $rel_val_terms * {rmod} +
asp_index.link * $rel_val_permalinks * {rmod} +
asp_index.tag * $rel_val_terms * {rmod} +
asp_index.customfield * $rel_val_cf * {rmod} +
asp_index.author * $rel_val_author * {rmod}
) as `relevance`
FROM
" . wd_asp()->db->table('index') . " as asp_index
$user_join
$add_join
{args_join}
WHERE
({like_query})
AND $post_types
$blog_query
$wpml_query
$polylang_query
$term_query
$user_query
AND $cf_select
$exclude_posts
$include_posts
$post_parents_select
$post_parents_exclude_select
$date_query
$post_fields_query
$add_where
{args_where}
{group_by}
LIMIT {limit}";
// Place the argument query fields
if ( isset($args['cpt_query']) && is_array($args['cpt_query']) ) {
$_mod_q = $args['cpt_query'];
foreach ( $_mod_q as &$qv ) {
$qv = str_replace($wpdb->posts . '.ID', 'asp_index.doc', $qv);
}
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array( $_mod_q['fields'], $_mod_q['join'], $_mod_q['where'], $_mod_q['orderby'] ),
$this->query
);
} else {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$this->query
);
}
$queries = array();
$results_arr = array();
// $words = $options['set_exactonly'] == 1 ? array($s) : $_s;
$words = $_s;
if ( empty($words) ) {
$queries[] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( '1', 1, $this->getPoolSize(), '' ), $this->query);
} elseif ( $kw_logic === 'orex' ) {
$rmod = 1;
$like_query = "(asp_index.term = '" . implode("' OR asp_index.term = '", $words) . "') AND asp_index.term_reverse <> ''";
$queries[] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( $like_query, $rmod, $this->getPoolSize(), '' ), $this->query);
} elseif ( $kw_logic === 'andex' ) {
foreach ( $words as $wk => $word ) {
$rmod = max(10 - ( $wk * 8 ), 1);
$like_query = "asp_index.term = '$word' AND asp_index.term_reverse <> ''";
$queries[] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( $like_query, $rmod, $this->getPoolSize($word), '' ), $this->query);
}
} else {
foreach ( $words as $wk => $word ) {
$rmod = max(10 - ( $wk * 8 ), 1);
$like_query = "asp_index.term LIKE '" . $word . "%' AND asp_index.term_reverse <> ''";
$queries[] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( $like_query, $rmod, $this->getPoolSize($word), '' ), $this->query);
$like_query = "asp_index.term_reverse LIKE '" . ( $_sr[ $wk ] ?? $sr ) . "%' AND asp_index.term_reverse <> ''";
$queries[] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( $like_query, intval($rmod / 2), $this->getPoolSize($word), '' ), $this->query);
}
}
/*---------------------- Post CPT IDs ---------------------------*/
if ( in_array('ids', $args['post_fields'], true) ) {
$queries['doc'] = str_replace(array( '{like_query}', '{rmod}', '{limit}', '{group_by}' ), array( "asp_index.doc LIKE '$s'", 1, $this->getPoolSize(), 'GROUP BY id' ), $this->query);
}
/*---------------------------------------------------------------*/
/*----------------------- Improved title and custom field search query ------------------*/
if (
$args['post_primary_order'] === 'relevance' &&
in_array('title', $args['post_fields'], true) && ( MB::strlen($s) > 2 || count($_s) === 0 )
) {
$rmod = 1000;
// Re-calculate the limit to slice the results to the real size
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['posts_limit'];
} else {
$limit = $args['posts_limit_override'];
}
if ( !$args['_ajax_search'] || $args['_show_more_results'] ) {
$limit = $limit * $this->remaining_limit_mod;
}
// Exact title query
$single_delimiter = count($_s) === 1 ? '___' : '';
$title_query = str_replace(
array( '{like_query}', '{rmod}', '{limit}', '{group_by}', 'asp_index.doc as id' ),
array( "(asp_index.term_reverse = '' AND asp_index.term LIKE '" . $s . $single_delimiter . "')", $rmod * 2, $limit, '', 'DISTINCT asp_index.doc as id' ),
$this->query
);
$results_arr['exact'] = $wpdb->get_results($title_query); // phpcs:ignore
// We reached the required limit, reset the other queries, as we don't need them
if ( count($results_arr['exact']) >= $limit ) {
$queries = array();
} else {
// partial query on "OR" and "AND"
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$title_query = str_replace(
array( '{like_query}', '{rmod}', '{limit}', '{group_by}', 'asp_index.doc as id' ),
array( "(asp_index.term_reverse = '' AND asp_index.term LIKE '$s%')", $rmod, $limit, '', 'DISTINCT asp_index.doc as id' ),
$this->query
);
} else { // partial query (starting with) until the first keyword for OREX and ANDEX
$title_query = str_replace(
array( '{like_query}', '{rmod}', '{limit}', '{group_by}', 'asp_index.doc as id' ),
array( "(asp_index.term_reverse = '' AND asp_index.term LIKE '$s %')", $rmod, $limit, '', 'DISTINCT asp_index.doc as id' ),
$this->query
);
}
$results_arr['starts_with'] = $wpdb->get_results($title_query); // phpcs:ignore
// We reached the required limit, reset the other queries, as we don't need them
if ( count($results_arr['starts_with']) >= $limit ) {
$queries = array();
}
}
}
/*---------------------------------------------------------------*/
if ( count($queries) > 0 ) {
foreach ( $queries as $k => $query ) {
$query = apply_filters('asp_query_indextable', $query, $args, $args['_id'], $args['_ajax_search']);
$results_arr[ $k ] = $wpdb->get_results($query); // phpcs:ignore
}
}
// Merge results depending on the logic
$results_arr = $this->mergeRawResults($results_arr, $kw_logic);
// We need to save this array with keys, will need the values later.
$this->raw_results = $results_arr;
// Do primary ordering here, because the results will slice, and we need the correct ones on the top
self::orderBy(
$results_arr,
array(
'engine' => $args['engine'],
'primary_ordering' => $args['post_primary_order'],
'primary_ordering_metatype' => $args['post_primary_order_metatype'],
'secondary_ordering' => $args['post_primary_order'], // PRIMARY ORDER ON PURPOSE!! -> Secondary does not apply when primary == secondary
)
);
// Re-calculate the limit to slice the results to the real size
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['posts_limit'];
} else {
$limit = $args['posts_limit_override'];
}
$this->results_count = count($results_arr) > $limit * $this->remaining_limit_mod ? $limit * $this->remaining_limit_mod : count($results_arr);
// For non-ajax search, results count needs to be limited to the maximum limit,
// ...as nothing is parsed beyond that
if ( !$args['_ajax_search'] && $this->results_count > $limit ) { // phpcs:ignore
$this->results_count = $limit;
}
// Apply new limit, but perserve the keys
$results_arr = array_slice($results_arr, $args['_call_num'] * $limit, $limit, true);
$this->results = $results_arr;
// Do some pre-processing
$this->preProcessResults();
$this->return_count = count($this->results);
}
/**
* Merges the initial results array, creating a union or intersection.
*
* The function also adds up the relevance values of the results object.
*
* @param array<int|string, array<ResultObj>> $results_arr
* @param "and"|"or"|"andex"|"orex" $kw_logic keyword logic (and, or, andex, orex)
* @return array<ResultObj> results array
*/
protected function mergeRawResults( array $results_arr, string $kw_logic = 'or' ): array {
// Store the improved title and cf results array temporarily
// We want these items to be the part of results, no matter what
$fixed_results = array();
foreach ( array( 'doc', 'exact', 'starts_with' ) as $key ) {
if ( isset($results_arr[ $key ]) ) {
/**
* Don't use $fixed_results[$key]
* PHP 8.1< does not support array unpacking with non-numeric keys
* ...$fixed_results will fail if the keys are numeric
*/
$fixed_results[] = $results_arr[ $key ];
unset($results_arr[ $key ]);
}
}
/*
* When using the "and" logic, the $results_arr contains the results in [term, term_reverse]
* results format. These should not be intersected with each other, so this small code
* snippet here divides the results array by groups of 2, then it merges ever pair to one result.
* This way it turns into [term1, term1_reverse, term2 ...] array to [term1 union term1_reversed, ...]
*
* This is only neccessary with the "and" logic. Others work fine.
*/
if ( $kw_logic === 'and' && $this->s !== '' ) {
$new_ra = array();
$i = 0;
$tmp_v = array();
foreach ( $results_arr as $_v ) {
if ( $i & 1 ) {
// odd, so merge the previous with the current
$new_ra[] = array_merge($tmp_v, $_v);
}
$tmp_v = $_v;
++$i;
}
$results_arr = $new_ra;
}
$final_results = array();
foreach ( array_merge($results_arr, $fixed_results) as $results ) {
foreach ( $results as $r ) {
if ( isset($final_results[ $r->blogid . 'x' . $r->id ]) ) {
$final_results[ $r->blogid . 'x' . $r->id ]->relevance += $r->relevance;
} else {
$final_results[ $r->blogid . 'x' . $r->id ] = $r;
}
}
}
if ( $kw_logic === 'or' || $kw_logic === 'orex' ) {
return $final_results;
}
foreach ( $results_arr as $results ) {
/**
* Why the array_merge($results, $title_results) ?
* -> Because here is an AND or ANDEX logic, so array intersections will be returned.
* All elements in the $title_results array not necessarily are a union of subset of each $results array.
* To make sure that the elements of $title_results are indeed used, merge it with the actual $results
* array. The $final_results at the end will contain all items from $title_results at all times.
*/
$final_results = array_uintersect(
$final_results,
array_merge($results, ...$fixed_results),
array( $this, 'compareResults' )
);
}
return $final_results;
}
public function getPoolSize( ?string $s = null ): int {
$args = $this->args;
$len = $s === null ? 100 : MB::strlen($s);
if ( $len <= 1 ) {
$pool_size = $args['it_pool_size_one'];
} elseif ( $len === 2 ) {
$pool_size = $args['it_pool_size_two'];
} elseif ( $len === 3 ) {
$pool_size = $args['it_pool_size_three'];
} else {
$pool_size = $args['it_pool_size_rest'];
}
$pool_size = intval($pool_size);
return max($pool_size, 100);
}
/**
* A custom comparison function for results intersection
*
* @param object{id: int, blogid: int} $a
* @param object{id: int, blogid: int} $b
*
* @return mixed
*/
protected function compareResults( object $a, object $b ) {
if ( $a->blogid === $b->blogid ) {
return $b->id - $a->id;
}
return $b->blogid - $a->blogid;
}
private function preProcessResults(): void {
// No results, save some resources
if ( count($this->results) === 0 ) {
return;
}
$pageposts = array();
$post_ids = array();
$the_posts = array();
$args = $this->args;
$sd = $args['_sd'] ?? array();
if ( $args['_ajax_search'] ) {
$start = 0;
$end = count($this->results);
} else {
/**
* Offset =>
* Positive -> Number of Index Table results displayed up until the current page
* Negative -> (abs) Number of other result types displayed up until (and including) the current page
*/
$offset = ( ( $args['page'] - 1 ) * $args['posts_per_page'] ) - $args['global_found_posts'];
$start = max($offset, 0);
$end = $start + $args['posts_per_page'] + ( min($offset, 0) );
$end = $end > count($this->results) ? count($this->results) : $end;
}
$this->start_offset = $start;
/**
* Do not use a for loop here, as the $this->results does not have numeric keys
*/
$k = 0;
foreach ( $this->results as $r ) {
if ( $k >= $start && $k < $end ) {
$post_ids[ $r->blogid ][] = $r->id;
}
if ( $k >= $end ) {
break;
}
++$k;
}
foreach ( $post_ids as $blogid => $the_ids ) {
$this->switchMultisiteBlog(intval($blogid));
$pargs = array(
'post__in' => $the_ids,
// DO NOT use orderby=post__in, causes problems
'posts_per_page' => -1,
'post_status' => 'any',
// WARNING: Do NOT use "any" as post_type, it will not work!!!
// @phpcs:ignore
'post_type' => !empty($args['_exclude_page_parent_child']) ?
array_merge($args['post_type'], array( 'page' )) : $args['post_type'],
);
/**
* Polylang workaround
* - Force any language, as the correct items are already returned by the index
* table engine.
* url: https://polylang.pro/doc/developpers-how-to/#all
*/
if ( function_exists('pll_the_languages') ) {
$pargs['lang'] = '';
}
/**
* @var WP_Post[] $get_posts
*/
$get_posts = get_posts($pargs);
foreach ( $get_posts as $gv ) {
$gv->blogid = $blogid; // @phpstan-ignore-line
}
// Resort by ID, because orderby=post__in causes issues in some cases
$sorted_get_posts = array();
foreach ( $the_ids as $id ) {
foreach ( $get_posts as $gp ) {
if ( $gp->ID === intval($id) ) {
$sorted_get_posts[] = $gp;
break;
}
}
}
/**
* @var WP_Post[] $the_posts
*/
$the_posts = array_merge($the_posts, $sorted_get_posts);
}
$this->restoreMultisiteBlog();
// Merge the posts with the raw results to a new array
foreach ( $the_posts as $r ) {
$new_result = new stdClass();
$new_result->id = $r->ID;
$new_result->blogid = $r->blogid; // @phpstan-ignore-line
$new_result->title = $r->post_title;
$new_result->post_title = $new_result->title;
$new_result->content = $r->post_content;
$new_result->excerpt = $r->post_excerpt;
$new_result->image = null;
if ( $sd['showauthor'] == 1 ) { // @phpcs:ignore
$post_user = get_user_by('id', $r->post_author);
if ( $post_user !== false ) {
if ( $sd['author_field'] === 'display_name' ) {
$new_result->author = $post_user->data->display_name;
} else {
$new_result->author = $post_user->data->user_login;
}
} else {
$new_result->author = null;
}
}
$new_result->date = $r->post_date;
$new_result->post_date = $new_result->date;
$new_result->post_modified = $r->post_modified;
$new_result->menu_order = $r->menu_order;
$key = $new_result->blogid . 'x' . $new_result->id;
// Get the relevance and priority values
$new_result->relevance = (int) $this->raw_results[ $key ]->relevance;
$new_result->priority = (int) $this->raw_results[ $key ]->priority;
$new_result->group_priority = (int) $this->raw_results[ $key ]->group_priority;
$new_result->p_type_priority = (int) $this->raw_results[ $key ]->p_type_priority;
$new_result->post_type = $this->raw_results[ $key ]->post_type;
$new_result->average_rating = floatval($this->raw_results[ $key ]->average_rating ?? 0);
$new_result->customfp = $this->raw_results[ $key ]->customfp ?? 1;
$new_result->customfs = $this->raw_results[ $key ]->customfs ?? 1;
$new_result->content_type = 'pagepost';
$new_result->g_content_type = 'post_page_cpt';
$pageposts[] = $new_result;
}
self::orderBy(
$pageposts,
array(
'engine' => $args['engine'],
'primary_ordering' => $args['post_primary_order'],
'primary_ordering_metatype' => $args['post_primary_order_metatype'],
'secondary_ordering' => $args['post_secondary_order'],
'secondary_ordering_metatype' => $args['post_secondary_order_metatype'],
)
);
$this->results = $pageposts;
}
}

View File

@@ -0,0 +1,481 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Misc\Priorities;
use WPDRMS\ASP\Utils\Str;
final class SearchMedia extends SearchMediaIndex {
protected function doSearch(): void {
global $wpdb;
global $q_config;
$args = $this->args;
$sd = $args['_sd'] ?? array();
// Prefixes and suffixes
$pre_field = $this->pre_field;
$suf_field = $this->suf_field;
$pre_like = $this->pre_like;
$suf_like = $this->suf_like;
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
$kw_logic = $args['keyword_logic'];
$q_config['language'] = $args['_qtranslate_lang'];
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
$postmeta_join = '';
if ( $args['_limit'] > 0 ) {
$this->remaining_limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$this->remaining_limit = $args['attachments_limit'];
} else {
$this->remaining_limit = $args['attachments_limit_override'];
}
$query_limit = $this->remaining_limit * $this->remaining_limit_mod;
if ( $this->remaining_limit <= 0 ) {
return;
}
// ------------------------- Statuses ---------------------------- //
// Attachments are inherited only
$post_statuses = '(' . $pre_field . $wpdb->posts . '.post_status' . $suf_field . " = 'inherit' )";
/*---------------------------------------------------------------*/
// ----------------------- Gather Types -------------------------- //
$post_types = "($wpdb->posts.post_type = 'attachment' )";
// --------------------------------------------------------------- //
// ------------------------ Categories/tags/taxonomies ----------------------
$term_query = $this->buildTermQuery( $wpdb->posts . '.ID', $wpdb->posts . '.post_type' );
// ---------------------------------------------------------------------
// ------------- Custom Fields with Custom selectors ------------- //
if ( $args['attachments_cf_filters'] ) {
$cf_select = $this->buildCffQuery( $wpdb->posts . '.ID' );
} else {
$cf_select = '(1)';
}
// --------------------------------------------------------------- //
// ------------------------- Mime Types -------------------------- //
$mime_types = '';
if ( !empty($args['attachment_mime_types']) ) {
$mime_types = "AND ( $wpdb->posts.post_mime_type IN ('" . implode("','", $args['attachment_mime_types']) . "') )";
}
// --------------------------------------------------------------- //
// ------------------------ Exclude id's ------------------------- //
$exclude_posts = '';
if ( !empty($args['attachment_exclude']) ) {
$exclude_posts = "AND ($wpdb->posts.ID NOT IN (" . implode(',', $args['attachment_exclude']) . '))';
}
// --------------------------------------------------------------- //
// ------------------------ Term JOIN ---------------------------- //
// If the search in terms is not active, we don't need this unnecessary big join
$term_join = '';
if ( $args['attachments_search_terms'] ) {
$term_join = "
LEFT JOIN $wpdb->term_relationships ON $wpdb->posts.ID = $wpdb->term_relationships.object_id
LEFT JOIN $wpdb->term_taxonomy ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id
LEFT JOIN $wpdb->terms ON $wpdb->term_taxonomy.term_id = $wpdb->terms.term_id";
}
// --------------------------------------------------------------- //
// ------------------------- WPML filter ------------------------- //
$wpml_query = '(1)';
if ( $args['_wpml_lang'] !== '' ) {
global $sitepress;
$site_lang_selected = false;
// Let us get the default site language if possible
if ( is_object($sitepress) && method_exists($sitepress, 'get_default_language') ) {
$site_lang_selected = $sitepress->get_default_language() === $args['_wpml_lang'];
}
$wpml_query = '
EXISTS (
SELECT DISTINCT(wpml.element_id)
FROM ' . $wpdb->prefix . "icl_translations as wpml
WHERE
$wpdb->posts.ID = wpml.element_id AND
wpml.language_code = '" . Str::escape( $args['_wpml_lang'] ) . "' AND
wpml.element_type IN ('post_attachment')
)";
/**
* For missing translations...
* If the site language is used, the translation can be non-existent
*/
if ( $args['_wpml_allow_missing_translations'] && $site_lang_selected ) {
$wpml_query = '
NOT EXISTS (
SELECT DISTINCT(wpml.element_id)
FROM ' . $wpdb->prefix . "icl_translations as wpml
WHERE
$wpdb->posts.ID = wpml.element_id AND
wpml.element_type IN ('post_attachment')
) OR
" . $wpml_query;
}
}
/*---------------------------------------------------------------*/
/*----------------------- Date filtering ------------------------*/
$date_query = '';
$date_query_parts = $this->get_date_query_parts();
if ( count($date_query_parts) > 0 ) {
$date_query = ' AND (' . implode(' AND ', $date_query_parts) . ') ';
}
/*---------------------------------------------------------------*/
/*----------------------- Exclude USER id -----------------------*/
$user_query = '';
if ( isset($args['post_user_filter']['include']) ) {
if ( !in_array(-1, $args['post_user_filter']['include']) ) { // phpcs:ignore
$user_query = "AND $wpdb->posts.post_author IN (" . implode(', ', $args['post_user_filter']['include']) . ')
';
}
}
if ( isset($args['post_user_filter']['exclude']) ) {
if ( !in_array(-1, $args['post_user_filter']['exclude']) ) { // phpcs:ignore
$user_query = "AND $wpdb->posts.post_author NOT IN (" . implode(', ', $args['post_user_filter']['exclude']) . ') ';
} else {
return;
}
}
/*---------------------------------------------------------------*/
/**
* Determine if the priorities table should be used or not.
*/
$priority_select = Priorities::count() > 0 ? '
IFNULL((
SELECT
aspp.priority
FROM ' . wd_asp()->db->table('priorities') . " as aspp
WHERE aspp.post_id = $wpdb->posts.ID AND aspp.blog_id = " . get_current_blog_id() . '
), 100)
' : 100;
/*---------------- Primary custom field ordering ----------------*/
$custom_field_selectp = '1 ';
if (
strpos($args['post_primary_order'], 'customfp') !== false &&
$args['_post_primary_order_metakey'] !== ''
) {
// @phpstan-ignore-next-line
$custom_field_selectp = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->postmeta
WHERE
$wpdb->postmeta.meta_key='" . esc_sql($args['_post_primary_order_metakey']) . "' AND
$wpdb->postmeta.post_id=$wpdb->posts.ID
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
/*--------------- Secondary custom field ordering ---------------*/
$custom_field_selects = '1 ';
if (
strpos($args['post_secondary_order'], 'customfs') !== false &&
$args['_post_secondary_order_metakey'] !== ''
) {
// @phpstan-ignore-next-line
$custom_field_selects = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->postmeta
WHERE
$wpdb->postmeta.meta_key='" . esc_sql($args['_post_secondary_order_metakey']) . "' AND
$wpdb->postmeta.post_id=$wpdb->posts.ID
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
$this->ordering['primary'] = $args['post_primary_order'];
$this->ordering['secondary'] = $args['post_secondary_order'];
$_primary_field = explode(' ', $this->ordering['primary']);
$this->ordering['primary_field'] = $_primary_field[0];
$orderby_primary = str_replace( 'post_', $wpdb->posts . '.post_', $args['post_primary_order'] );
$orderby_secondary = str_replace( 'post_', $wpdb->posts . '.post_', $args['post_secondary_order'] );
if ( $args['post_primary_order_metatype'] === 'numeric' ) {
$orderby_primary = str_replace('customfp', 'CAST(customfp as SIGNED)', $orderby_primary);
}
if ( $args['post_secondary_order_metatype'] === 'numeric' ) {
$orderby_secondary = str_replace('customfs', 'CAST(customfs as SIGNED)', $orderby_secondary);
}
/**
* This is the main query.
*
* The ttid field is a bit tricky as the term_taxonomy_id doesn't always equal term_id,
* so we need the LEFT JOINS :(
*/
$this->query = "
SELECT
{args_fields}
$wpdb->posts.ID as id,
$this->c_blogid as `blogid`,
$wpdb->posts.post_title as `title`,
$wpdb->posts.post_date as `date`,
$wpdb->posts.post_content as `content`,
$wpdb->posts.post_excerpt as `excerpt`,
$wpdb->posts.post_type as `post_type`,
$wpdb->posts.post_mime_type as post_mime_type,
$wpdb->posts.guid as guid,
'attachment' as `content_type`,
'attachments' as `g_content_type`,
(SELECT
$wpdb->users." . w_isset_def($sd['author_field'], 'display_name') . " as `author`
FROM $wpdb->users
WHERE $wpdb->users.ID = $wpdb->posts.post_author
) as `author`,
'' as ttid,
$wpdb->posts.post_type as `post_type`,
$priority_select as `priority`,
1 AS group_priority,
1 as `p_type_priority`,
{relevance_query} as `relevance`,
$custom_field_selectp as `customfp`,
$custom_field_selects as `customfs`
FROM $wpdb->posts
{postmeta_join}
$term_join
{args_join}
WHERE
$post_types
AND $post_statuses
AND {like_query}
$exclude_posts
$mime_types
$term_query
$date_query
$user_query
AND $cf_select
AND ($wpml_query)
{args_where}
GROUP BY
{args_groupby}
ORDER BY {args_orderby} priority DESC, $orderby_primary, $orderby_secondary
LIMIT $query_limit";
// Place the argument query fields
if ( isset($args['attachment_query']) && is_array($args['attachment_query']) ) {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array( $args['attachment_query']['fields'], $args['attachment_query']['join'], $args['attachment_query']['where'], $args['attachment_query']['orderby'] ),
$this->query
);
} else {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$this->query
);
}
if ( isset($args['attachment_query']['groupby']) && $args['attachment_query']['groupby'] !== '' ) {
$this->query = str_replace('{args_groupby}', $args['attachment_query']['groupby'], $this->query);
} else {
$this->query = str_replace('{args_groupby}', "$wpdb->posts.ID", $this->query);
}
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
/*----------------------- Title query ---------------------------*/
if ( $args['attachments_search_title'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
( ' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '$s%')
then " . ( w_isset_def($sd['etitleweight'], 10) * 2 ) . ' else 0 end)';
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
// The first word relevance is higher
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
}
}
}
/*---------------------------------------------------------------*/
/*---------------------- Content query --------------------------*/
if ( $args['attachments_search_content'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['econtentweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
/*------------------- Caption/Excerpt query ---------------------*/
if ( $args['attachments_search_caption'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_excerpt' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
}
}
/*---------------------------------------------------------------*/
/*-------------------------- IDs query --------------------------*/
if ( $args['attachments_search_ids'] ) {
$parts[] = "($wpdb->posts.ID LIKE '$word')";
}
/*---------------------------------------------------------------*/
/*------------------------ Term query ---------------------------*/
if ( $args['attachments_search_terms'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " = '" . $word . "')";
}
}
/*---------------------------------------------------------------*/
/*---------------------- Custom Fields --------------------------*/
if ( $args['post_custom_fields_all'] ) {
$args['post_custom_fields'] = array( 'all' );
}
if ( count($args['post_custom_fields']) > 0 ) {
$postmeta_join = "LEFT JOIN $wpdb->postmeta ON $wpdb->postmeta.post_id = $wpdb->posts.ID";
foreach ( $args['post_custom_fields'] as $cfield ) {
$key_part = $args['post_custom_fields_all'] ? '' : "$wpdb->postmeta.meta_key='$cfield' AND ";
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$parts[] = "( $key_part " . $pre_field . $wpdb->postmeta . '.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = "( $key_part
(" . $pre_field . $wpdb->postmeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->postmeta . '.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->postmeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->postmeta . '.meta_value' . $suf_field . " = '" . $word . "') )";
}
if ( !$relevance_added ) {
if ( $cfield === 'author_field_name' ) {
$relevance_parts[] = "(case when
(EXISTS (SELECT 1 FROM $wpdb->postmeta as cfre WHERE cfre.post_id = $wpdb->posts.ID AND cfre.meta_key = '$cfield' AND
(cfre.meta_value" . $suf_field . " LIKE '%" . $s . "%')))
then 100 else 0 end)";
}
if ( $cfield === 'fulltext_field_name' ) {
$relevance_parts[] = "(case when
(EXISTS (SELECT 1 FROM $wpdb->postmeta as cfre WHERE cfre.post_id = $wpdb->posts.ID AND cfre.meta_key = '$cfield' AND
(cfre.meta_value" . $suf_field . " LIKE '%" . $s . "%')))
then 10 else 0 end)";
}
}
}
}
/*---------------------------------------------------------------*/
$this->parts[] = array( $parts, $relevance_parts );
$relevance_added = true;
}
// Add the meta join if needed...
$this->query = str_replace( '{postmeta_join}', $postmeta_join, $this->query );
$querystr = $this->buildQuery($this->parts);
$querystr = apply_filters('asp_query_attachments', $querystr, $args, $args['_id'], $args['_ajax_search']);
$attachments = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($attachments);
// For non-ajax search, results count needs to be limited to the maximum limit, as nothing is parsed beyond that
if ( !$args['_ajax_search'] && $this->results_count > $this->remaining_limit ) {
$this->results_count = $this->remaining_limit;
}
$attachments = array_slice($attachments, $args['_call_num'] * $this->remaining_limit, $this->remaining_limit);
$this->results = $attachments;
$this->return_count = count($this->results);
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\AdvancedField\AdvancedFieldParser;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Pdf;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
class SearchMediaIndex extends SearchIndex {
protected function doSearch(): void {
$args = &$this->args;
$args['post_type'] = array( 'attachment' );
$args['posts_limit'] = $args['attachments_limit'];
$args['posts_limit_override'] = $args['attachments_limit_override'];
$args['post_not_in2'] = $args['attachment_exclude'];
parent::doSearch();
}
protected function postProcess(): void {
$args = &$this->args;
$s = $this->s;
$_s = $this->_s;
$sd = $args['_sd'] ?? array();
// No post-processing if the search data param is missing or explicitly set
if ( empty($args['_sd']) || !$args['_post_process'] ) {
return;
}
foreach ( $this->results as $k => $r ) {
if ( !isset($r->post_mime_type) ) {
$r->post_mime_type = get_post_mime_type( $r->id );
}
if ( !isset($r->guid) ) {
$r->guid = get_the_guid( $r->id );
}
$r->title = get_the_title($r->id);
if ( !empty($sd['advtitlefield']) ) {
$r->title = AdvancedFieldParser::instance()->parse($sd['advtitlefield'], $r);
}
$r->title = wd_substr_at_word($r->title, $sd['post_type_res_title_length']);
$image_settings = $sd['image_options'];
$image_args = array(
'get_content' => false,
'get_excerpt' => false,
'image_sources' => array(
$image_settings['image_source1'],
$image_settings['image_source2'],
$image_settings['image_source3'],
$image_settings['image_source4'],
$image_settings['image_source5'],
),
'image_source_size' => $image_settings['image_source_featured'] === 'original' ? 'full' : $image_settings['image_source_featured'],
'image_default' => $image_settings['image_default'],
'image_number' => $sd['image_parser_image_number'],
'image_custom_field' => $image_settings['image_custom_field'],
'exclude_filenames' => $sd['image_parser_exclude_filenames'],
'image_width' => $image_settings['image_width'],
'image_height' => $image_settings['image_height'],
'apply_the_content' => $image_settings['apply_content_filter'],
'image_cropping' => $image_settings['image_cropping'],
'image_transparency' => $image_settings['image_transparency'],
'image_bg_color' => $image_settings['image_bg_color'],
);
if (
$r->post_mime_type === 'application/pdf' &&
$args['attachment_pdf_image']
) {
$r->image = Pdf::getThumbnail($r->id, false, $image_args['image_source_size']);
}
if ( empty($r->image) && $args['attachment_use_image'] && $r->guid !== '' ) {
$r->image = Post::parseImage($r, $image_args);
}
// --------------------------------- URL -----------------------------------
if ( $args['attachment_link_to'] === 'file' ) {
$_url = wp_get_attachment_url( $r->id );
if ( $_url !== false ) {
$this->results[ $k ]->link = $_url;
}
} elseif ( $args['attachment_link_to'] === 'parent' ) {
$parent_id = wp_get_post_parent_id( $r->id );
if ( !is_wp_error($parent_id) && !empty($parent_id) ) {
// Change the link to parent post permalink
$r->link = get_permalink( $parent_id );
} elseif ( $args['attachment_link_to_secondary'] === 'file' ) {
$_url = wp_get_attachment_url($r->id);
if ( $_url !== false ) {
$this->results[ $k ]->link = $_url;
}
}
} else {
$_url = get_attachment_link($r->id);
if ( !empty($_url) ) {
$this->results[ $k ]->link = $_url;
}
}
// --------------------------------------------------------------------------
if ( $r->content === '' ) {
$_content = get_post_meta($r->id, '_asp_attachment_text', true);
$_content = wd_strip_tags_ws($_content, $sd['striptagsexclude']);
} else {
$_content = $r->content;
}
// Get the words from around the search phrase, or just the description
if ( $_content !== '' ) {
if ( $sd['description_context'] && count($_s) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( MB::strlen($_content) > $sd['descriptionlength'] ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
}
$r->content = $_content;
$description_length = $sd['descriptionlength'];
if ( !empty($sd['advdescriptionfield']) ) {
$cb = function ( $value, $field, $results, $field_args ) use ( $description_length, $sd, $s, $_s ) {
if ( strpos($field, 'html') !== false || ( isset($field_args['html']) && $field_args['html'] ) ) {
return $value;
}
$value = Post::dealWithShortcodes($value, $sd['shortcode_op'] === 'remove');
$strip_tags = $field_args['strip_tags'] ?? 1;
if ( !$strip_tags ) {
return $value;
}
$value = Html::stripTags($value, $sd['striptagsexclude']);
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$value = Str::getContext($value, $description_length, $sd['description_context_depth'], $s, $_s);
} elseif ( $value !== '' && ( MB::strlen( $value ) > $description_length ) ) {
$value = wd_substr_at_word($value, $description_length);
}
return $value;
};
add_filter('asp_cpt_advanced_field_value', $cb, 10, 4);
$r->content = AdvancedFieldParser::instance()->parse($sd['advdescriptionfield'], $r);
remove_filter('asp_cpt_advanced_field_value', $cb);
}
$r->content = Str::fixSSLURLs(wd_closetags($r->content));
// --------------------------------- DATE -----------------------------------
if ( isset($sd['showdate']) && $sd['showdate'] ) {
$post_time = strtotime($this->results[ $k ]->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$this->results[ $k ]->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
}

View File

@@ -0,0 +1,309 @@
<?php
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchPeepsoActivities extends SearchPostTypes {
/** @noinspection DuplicatedCode */
protected function doSearch(): void {
global $wpdb;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
$s = $this->s;
$_s = $this->_s;
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['peepso_activities_limit'];
} else {
$limit = $args['peepso_activities_limit_override'];
}
$query_limit = $limit * 3;
if ( $limit <= 0 ) {
return;
}
if ( count($args['peepso_activity_types']) === 0 ) {
return;
}
// Prefixes and suffixes
$pre_field = '';
$suf_field = '';
$pre_like = '';
$suf_like = '';
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
$kw_logic = $args['keyword_logic'];
$post_types = "$wpdb->posts.post_type IN ('" . implode("','", $args['peepso_activity_types']) . "')";
/*----------------------- Date filtering ------------------------*/
$date_query = '';
$date_query_parts = $this->get_date_query_parts();
if ( count($date_query_parts) > 0 ) {
$date_query = ' AND (' . implode(' AND ', $date_query_parts) . ') ';
}
/*---------------------------------------------------------------*/
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
/*---------------------- Content query --------------------------*/
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['econtentweight'], 10) . ' else 0 end)';
}
/*---------------------------------------------------------------*/
$this->parts[] = array( $parts, $relevance_parts );
$relevance_added = true;
}
/*------------------------ Group Privacy --------------------------*/
$peeps_privacy_query = '';
if ( !empty($args['peepso_group_activity_privacy']) ) {
$group_ids = is_array($args['peepso_group_activity_privacy']) ? $args['peepso_group_activity_privacy'] : explode(',', $args['peepso_group_activity_privacy']);
$group_ids = implode(',', $group_ids);
$peeps_privacy_query = "
AND (EXISTS (SELECT 1 FROM $wpdb->postmeta pgm
WHERE pgm.post_id = apm.meta_value AND
pgm.meta_key LIKE 'peepso_group_privacy' AND
pgm.meta_value IN ($group_ids)
))
";
}
/*---------------------------------------------------------------*/
/*-------------------- Restrict following -----------------------*/
$follow_query = '';
if ( $args['peepso_activity_follow'] ) {
$user_id = get_current_user_id();
$follow_query = ' AND (EXISTS(SELECT 1
FROM ' . $wpdb->prefix . "peepso_group_followers gf
WHERE
apm.meta_value = gf.gf_group_id AND
gf_user_id = $user_id AND
gf_follow = 1
))";
}
/*---------------------------------------------------------------*/
/*------------------------ Exclude ids --------------------------*/
if ( !empty($args['peepso_activity_not_in']) ) {
$exclude_posts = "AND ($wpdb->posts.ID NOT IN (" . ( is_array($args['peepso_activity_not_in']) ? implode(',', $args['peepso_activity_not_in']) : $args['peepso_activity_not_in'] ) . '))';
} else {
$exclude_posts = '';
}
/*---------------------------------------------------------------*/
/*----------------------- Exclude USER id -----------------------*/
$user_query = '';
if ( isset($args['post_user_filter']['include']) ) {
if ( !in_array(-1, $args['post_user_filter']['include']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->posts.post_author IN (" . implode(', ', $args['post_user_filter']['include']) . ')
';
}
}
if ( isset($args['post_user_filter']['exclude']) ) {
if ( !in_array(-1, $args['post_user_filter']['exclude']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->posts.post_author NOT IN (" . implode(', ', $args['post_user_filter']['exclude']) . ') ';
} else {
return;
}
}
/*---------------------------------------------------------------*/
if (
strpos($args['post_primary_order'], 'customfp') !== false ||
strpos($args['post_primary_order'], 'menu_order') !== false
) {
$orderby_primary = 'relevance DESC';
} else {
$orderby_primary = str_replace('post_', '', $args['post_primary_order']);
}
if (
strpos($args['post_secondary_order'], 'customfs') !== false ||
strpos($args['post_secondary_order'], 'menu_order') !== false
) {
$orderby_secondary = 'date DESC';
} else {
$orderby_secondary = str_replace('post_', '', $args['post_secondary_order']);
}
$this->query = "
SELECT
$wpdb->posts.ID as id,
pa.act_id as activity_id,
pa.act_comment_object_id as parent_activity_id,
apm.meta_value as group_id,
$this->c_blogid as `blogid`,
$wpdb->posts.post_type as `post_type`,
$wpdb->posts.post_author as user_id,
$wpdb->posts.post_title as `title`,
$wpdb->posts.post_content as `content`,
$wpdb->posts.post_excerpt as `excerpt`,
'' as `author`,
'peepso_activity' as `content_type`,
'peepso_activities' as `g_content_type`,
$wpdb->posts.post_date as `date`,
{relevance_query} as `relevance`
FROM
$wpdb->posts
LEFT JOIN " . $wpdb->prefix . "peepso_activities pa ON pa.act_external_id = $wpdb->posts.ID
LEFT JOIN
$wpdb->postmeta apm ON apm.post_id = IF((pa.act_comment_object_id = 0), $wpdb->posts.ID, pa.act_comment_object_id) AND
apm.meta_key LIKE 'peepso_group_id'
WHERE
$post_types
$peeps_privacy_query
$date_query
$user_query
$follow_query
AND {like_query}
$exclude_posts
GROUP BY
$wpdb->posts.ID
ORDER BY $orderby_primary, $orderby_secondary
LIMIT " . $query_limit;
$querystr = $this->buildQuery( $this->parts );
$results = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($results);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$results = array_slice($results, $args['_call_num'] * $limit, $limit);
$this->results = &$results;
$this->return_count = count($this->results);
}
/** @noinspection PhpFullyQualifiedNameUsageInspection
* @noinspection DuplicatedCode
*/
public function postProcess(): void {
$r = &$this->results;
$s = $this->s;
$_s = $this->_s;
$args = $this->args;
$sd = $args['_sd'] ?? array();
if ( class_exists('\PeepSo') && class_exists('\PeepSoActivity') ) {
foreach ( $r as $k => $v ) {
if ( $v->post_type === 'peepso-post' ) {
/* @noinspection All */
$v->link = \PeepSo::get_page('activity_status') . $v->title . '/';
} else {
$peepo_activity = \PeepSoActivity::get_instance();
$parent_post = get_post($v->parent_activity_id);
$parent_activity = $peepo_activity->get_activity_data($v->parent_activity_id, 8);
// Link structure -> link#comment. + parent activity ID + parent (activity) post ID + activity ID + (activity) post ID
// @phpstan-ignore-next-line
$v->link = \PeepSo::get_page('activity_status') . $parent_post->post_title . '/#comment.' . $parent_activity->act_id . '.' . $v->parent_activity_id . '.' . $v->activity_id . '.' . $v->id;
}
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
// Remove any mentions
/* @noinspection All */
$v->content = preg_replace('/@peepso_user_[0-9]{1,5}\((.*?)\).*?/i', '$1', $v->content);
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = wd_closetags($_content);
$v->title = wd_substr_at_word($v->content, 120);
if ( MB::strlen($v->content) > MB::strlen($v->title) ) {
$v->title .= '..';
}
/* Remove the results in polaroid mode */
if ( $args['_ajax_search'] && empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
unset($this->results[ $k ]);
continue;
}
// --------------------------------- DATE -----------------------------------
if ( isset($sd['showdate']) && $sd['showdate'] ) {
$post_time = strtotime($v->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$v->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
}
}

View File

@@ -0,0 +1,349 @@
<?php /** @noinspection DuplicatedCode */
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchPeepsoGroups extends SearchPostTypes {
protected function doSearch(): void {
global $wpdb;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
$s = $this->s;
$_s = $this->_s;
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['peepso_groups_limit'];
} else {
$limit = $args['peepso_groups_limit_override'];
}
$query_limit = $limit * 3;
if ( $limit <= 0 ) {
return;
}
// Prefixes and suffixes
$pre_field = '';
$suf_field = '';
$pre_like = '';
$suf_like = '';
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
$kw_logic = $args['keyword_logic'];
$category_join = '';
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
/*----------------------- Title query ---------------------------*/
if ( in_array('title', $args['peepso_group_fields'], true) ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
( ' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '$s%')
then " . ( w_isset_def($sd['etitleweight'], 10) * 2 ) . ' else 0 end)';
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
// The first word relevance is higher
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_title' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
}
}
}
/*---------------------------------------------------------------*/
/*---------------------- Content query --------------------------*/
if ( in_array('content', $args['peepso_group_fields'], true) ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$parts[] = '( ' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['contentweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->posts . '.post_content' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['econtentweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
/*----------------------- Category query ---------------------------*/
if ( in_array('categories', $args['peepso_group_fields'], true) ) {
if ( $category_join === '' ) {
$category_join = '
LEFT JOIN ' . $wpdb->prefix . "peepso_group_categories pgc ON pgc.gm_group_id = $wpdb->posts.ID
LEFT JOIN $wpdb->posts as pcj ON pcj.ID = pgc.gm_cat_id
";
}
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$parts[] = '( ' . $pre_field . 'pcj.post_title' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
( ' . $pre_field . 'pcj.post_title' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . 'pcj.post_title' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . 'pcj.post_title' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . 'pcj.post_title' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
$relevance_parts[] = '(case when
(' . $pre_field . 'pcj.post_title' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
$this->parts[] = array( $parts, $relevance_parts );
$relevance_added = true;
}
/*----------------------- Date filtering ------------------------*/
$date_query = '';
$date_query_parts = $this->get_date_query_parts();
if ( count($date_query_parts) > 0 ) {
$date_query = ' AND (' . implode(' AND ', $date_query_parts) . ') ';
}
/*---------------------------------------------------------------*/
/*------------------------ Group Privacy --------------------------*/
if ( !empty($args['peepso_group_privacy']) ) {
$group_ids = is_array($args['peepso_group_privacy']) ? $args['peepso_group_privacy'] : explode(',', $args['peepso_group_privacy']);
$group_ids = implode(',', $group_ids);
$peeps_privacy_query = "
AND (EXISTS (SELECT 1 FROM $wpdb->postmeta pgm
WHERE pgm.post_id = $wpdb->posts.ID AND
pgm.meta_key LIKE 'peepso_group_privacy' AND
pgm.meta_value IN ($group_ids)
))
";
} else {
return;
}
/*---------------------------------------------------------------*/
/*------------------------ Exclude ids --------------------------*/
if ( !empty($args['peepso_group_not_in']) ) {
$exclude_posts = "AND ($wpdb->posts.ID NOT IN (" . ( is_array($args['peepso_group_not_in']) ? implode(',', $args['peepso_group_not_in']) : $args['peepso_group_not_in'] ) . '))';
} else {
$exclude_posts = '';
}
/*---------------------------------------------------------------*/
/*----------------------- Exclude USER id -----------------------*/
$user_query = '';
if ( isset($args['post_user_filter']['include']) ) {
if ( !in_array(-1, $args['post_user_filter']['include']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->posts.post_author IN (" . implode(', ', $args['post_user_filter']['include']) . ')
';
}
}
if ( isset($args['post_user_filter']['exclude']) ) {
if ( !in_array(-1, $args['post_user_filter']['exclude']) ) { // @phpcs:ignore
$user_query = "AND $wpdb->posts.post_author NOT IN (" . implode(', ', $args['post_user_filter']['exclude']) . ') ';
} else {
return;
}
}
/*---------------------------------------------------------------*/
if (
strpos($args['post_primary_order'], 'customfp') !== false ||
strpos($args['post_primary_order'], 'menu_order') !== false
) {
$orderby_primary = 'relevance DESC';
} else {
$orderby_primary = str_replace('post_', '', $args['post_primary_order']);
}
if (
strpos($args['post_secondary_order'], 'customfs') !== false ||
strpos($args['post_secondary_order'], 'menu_order') !== false
) {
$orderby_secondary = 'date DESC';
} else {
$orderby_secondary = str_replace('post_', '', $args['post_secondary_order']);
}
$this->query = "
SELECT
$wpdb->posts.ID as id,
$this->c_blogid as `blogid`,
'peepso-group' as `post_type`,
$wpdb->posts.post_author as user_id,
$wpdb->posts.post_title as `title`,
$wpdb->posts.post_content as `content`,
$wpdb->posts.post_excerpt as `excerpt`,
'' as `author`,
'peepso_group' as `content_type`,
'peepso_groups' as `g_content_type`,
$wpdb->posts.post_date as `date`,
{relevance_query} as `relevance`
FROM
$wpdb->posts
$category_join
WHERE
$wpdb->posts.post_type = 'peepso-group'
$peeps_privacy_query
$date_query
$user_query
AND {like_query}
$exclude_posts
GROUP BY
$wpdb->posts.ID
ORDER BY $orderby_primary, $orderby_secondary
LIMIT " . $query_limit;
$querystr = $this->buildQuery( $this->parts );
$results = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($results);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$results = array_slice($results, $args['_call_num'] * $limit, $limit);
$this->results = &$results;
$this->return_count = count($this->results);
}
/**
* @noinspection PhpFullyQualifiedNameUsageInspection
* @noinspection PhpUndefinedClassInspection
*/
public function postProcess(): void {
$r = &$this->results;
$s = $this->s;
$_s = $this->_s;
$args = $this->args;
$sd = $args['_sd'] ?? array();
if ( !class_exists('\\PeepSoGroup') ) {
return;
}
foreach ( $r as $k => $v ) {
$pg = new \PeepSoGroup($v->id);
$v->link = $pg->get_url();
$v->title = $pg->name;
// Get the image
$image_settings = $sd['image_options'];
if ( $image_settings['show_images'] ) {
$im = $pg->get_cover_url();
if ( !$image_settings['image_cropping'] ) {
$v->image = $im;
} elseif ( strpos($im, 'mshots/v1') === false ) {
$bfi_params = array(
'width' => $image_settings['image_width'],
'height' => $image_settings['image_height'],
'crop' => true,
);
if ( !$image_settings['image_transparency'] ) {
$bfi_params['color'] = wpdreams_rgb2hex($image_settings['image_bg_color']);
}
$v->image = asp_bfi_thumb($im, $bfi_params);
} else {
$v->image = $im;
}
}
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = Str::fixSSLURLs( wd_closetags($_content) );
/* Remove the results in polaroid mode */
if ( $args['_ajax_search'] && empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres' ) {
unset($this->results[ $k ]);
continue;
}
// --------------------------------- DATE -----------------------------------
if ( isset($sd['showdate']) && $sd['showdate'] ) {
$post_time = strtotime($v->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$v->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,470 @@
<?php /** @noinspection DuplicatedCode */
namespace WPDRMS\ASP\Search;
use WP_Term;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchTaxonomyTerms extends SearchPostTypes {
protected function doSearch(): void {
global $wpdb;
global $q_config;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
$termmeta_join = '';
// Prefixes and suffixes
$pre_field = $this->pre_field;
$suf_field = $this->suf_field;
$pre_like = $this->pre_like;
$suf_like = $this->suf_like;
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
$kw_logic = $args['keyword_logic'];
$q_config['language'] = $args['_qtranslate_lang'];
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['taxonomies_limit'];
} else {
$limit = $args['taxonomies_limit_override'];
}
if ( $limit <= 0 ) {
return;
}
$query_limit = $limit * $this->remaining_limit_mod;
/*----------------------- Gather Types --------------------------*/
$taxonomies = "( $wpdb->term_taxonomy.taxonomy IN ('" . implode("','", $args['taxonomy_include']) . "') )";
/*---------------------------------------------------------------*/
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
/*----------------------- Title query ---------------------------*/
if ( $args['taxonomy_terms_search_titles'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->terms . '.name' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE '$s%')
then " . ( w_isset_def($sd['etitleweight'], 10) * 2 ) . ' else 0 end)';
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->terms . '.name' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['etitleweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
/*--------------------- Description query -----------------------*/
if ( $args['taxonomy_terms_search_description'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->term_taxonomy . '.description' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['contentweight'], 8) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
if ( $args['taxonomy_terms_search_term_meta'] ) {
if ( $termmeta_join === '' ) {
$termmeta_join = " LEFT JOIN $wpdb->termmeta tm ON tm.term_id = $wpdb->terms.term_id";
}
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . 'tm.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . 'tm.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . 'tm.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . 'tm.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . 'tm.meta_value' . $suf_field . " = '" . $word . "')";
}
}
if ( !empty($parts) ) {
$this->parts[] = array( $parts, $relevance_parts );
}
$relevance_added = true;
}
/*------------------------ Exclude id's -------------------------*/
$exclude_terms = '';
if ( !empty($args['taxonomy_terms_exclude']) ) {
$exclude_terms = " AND ($wpdb->terms.term_id NOT IN (" . ( is_array($args['taxonomy_terms_exclude']) ? implode(',', $args['taxonomy_terms_exclude']) : $args['taxonomy_terms_exclude'] ) . '))';
}
if ( !empty($args['taxonomy_terms_exclude2']) ) {
$exclude_terms .= " AND ($wpdb->terms.term_id NOT IN (" . implode(',', $args['taxonomy_terms_exclude2']) . '))';
}
/*---------------------------------------------------------------*/
/*------------------- Exclude empty terms -----------------------*/
$exclude_empty = '';
if ( $args['taxonomy_terms_exclude_empty'] ) {
$exclude_empty = " AND ($wpdb->term_taxonomy.count > 0) ";
}
/*---------------------------------------------------------------*/
/*----------------------- POLYLANG filter -----------------------*/
$polylang_query = '';
if ( $args['_polylang_lang'] !== '' ) {
$languages = get_terms(
array(
'hide_empty' => false,
'taxonomy' => 'term_language',
'fields' => 'ids',
'orderby' => 'term_group',
'slug' => 'pll_' . $args['_polylang_lang'],
)
);
if ( !empty($languages) && !is_wp_error($languages) && isset($languages[0]) ) {
$polylang_query = " AND (
$wpdb->term_taxonomy.term_taxonomy_id IN ( SELECT DISTINCT(tr.object_id)
FROM $wpdb->term_relationships AS tr
LEFT JOIN $wpdb->term_taxonomy as tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'term_language')
WHERE tt.term_id = $languages[0]
) )";
}
}
/*---------------------------------------------------------------*/
// ------------------------- WPML filter ------------------------- //
// New sub-select method instead of join
$wpml_query = '(1)';
if ( $args['_wpml_lang'] !== '' ) {
$wpml_query = '
EXISTS (
SELECT DISTINCT(wpml.element_id)
FROM ' . $wpdb->prefix . "icl_translations as wpml
WHERE
$wpdb->term_taxonomy.term_taxonomy_id = wpml.element_id AND
wpml.language_code LIKE '" . Str::escape($args['_wpml_lang']) . "' AND
wpml.element_type LIKE CONCAT('tax_%')
)";
}
/*---------------------------------------------------------------*/
/*-------------- Additional Query parts by Filters --------------*/
/**
* Use these filters to add additional parts to the select, join or where
* parts of the search query.
*/
$add_select = apply_filters('asp_term_query_add_select', '', $args, $this->s, $this->_s);
$add_join = apply_filters('asp_term_query_add_join', '', $args, $this->s, $this->_s);
$add_where = apply_filters('asp_term_query_add_where', '', $args, $this->s, $this->_s);
/*---------------------------------------------------------------*/
if (
strpos($args['post_primary_order'], 'customfp') !== false ||
strpos($args['post_primary_order'], 'modified') !== false ||
strpos($args['post_primary_order'], 'menu_order') !== false
) {
$orderby_primary = 'relevance DESC';
} else {
$orderby_primary = str_replace('post_', '', $args['post_primary_order']);
}
if (
strpos($args['post_secondary_order'], 'customfs') !== false ||
strpos($args['post_secondary_order'], 'modified') !== false ||
strpos($args['post_secondary_order'], 'menu_order') !== false
) {
$orderby_secondary = 'date DESC';
} else {
$orderby_secondary = str_replace('post_', '', $args['post_secondary_order']);
}
$this->query = "
SELECT
$add_select
{args_fields}
$wpdb->terms.name as `title`,
$wpdb->terms.term_id as id,
$this->c_blogid as `blogid`,
$wpdb->term_taxonomy.description as `content`,
'' as `date`,
'' as `author`,
$wpdb->term_taxonomy.taxonomy as taxonomy,
'term' as `content_type`,
'terms' as `g_content_type`,
{relevance_query} as `relevance`
FROM
$wpdb->terms
LEFT JOIN $wpdb->term_taxonomy ON $wpdb->terms.term_id = $wpdb->term_taxonomy.term_id
$termmeta_join
$add_join
{args_join}
WHERE
$taxonomies
AND {like_query}
$exclude_terms
$exclude_empty
AND $wpml_query
$polylang_query
$add_where
{args_where}
GROUP BY
{args_groupby}
";
$this->query .= " ORDER BY {args_orderby} $orderby_primary, $orderby_secondary, $wpdb->terms.name ASC
LIMIT " . $query_limit;
// Place the argument query fields
if ( isset($args['term_query']) && is_array($args['term_query']) ) {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array( $args['term_query']['fields'], $args['term_query']['join'], $args['term_query']['where'], $args['term_query']['orderby'] ),
$this->query
);
} else {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$this->query
);
}
if ( isset($args['term_query']['groupby']) && $args['term_query']['groupby'] !== '' ) {
$this->query = str_replace('{args_groupby}', $args['term_query']['groupby'], $this->query);
} else {
$this->query = str_replace('{args_groupby}', "$wpdb->terms.term_id", $this->query);
}
$querystr = $this->buildQuery( $this->parts );
$querystr = apply_filters('asp_query_terms', $querystr, $args, $args['_id'], $args['_ajax_search']);
$term_res = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($term_res);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$term_res = array_slice($term_res, $args['_call_num'] * $limit, $limit);
$this->results = $term_res;
$this->return_count = count($this->results);
}
protected function postProcess(): void {
$args = &$this->args;
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
if ( !isset($args['_sd']) ) {
$sd = array();
} else {
$sd = $args['_sd'];
}
$term_res = $this->results;
// Get term affected post count if enabled
if ( $sd['display_number_posts_affected'] ) {
foreach ( $term_res as $v ) {
$term = get_term_by('id', $v->id, $v->taxonomy);
if ( $term instanceof WP_Term ) {
$v->title .= ' (' . $term->count . ')';
}
}
}
$image_settings = $sd['image_options'];
if ( $image_settings['show_images'] ) {
foreach ( $term_res as $result ) {
if ( !empty($result->image) ) {
continue;
}
$image = '';
/* WooCommerce Term image integration */
if ( function_exists('get_term_meta') ) {
$thumbnail_id = get_term_meta( $result->id, 'thumbnail_id', true );
if ( !is_wp_error($thumbnail_id) && !empty($thumbnail_id) ) {
$image = wp_get_attachment_url($thumbnail_id);
}
}
// Categories images plugin
if ( function_exists('z_taxonomy_image_url') ) {
/** @noinspection PhpUndefinedFunctionInspection */
$image = z_taxonomy_image_url($result->id);
}
// Try parsing term meta
if ( empty($image) && !empty($sd['tax_image_custom_field']) ) {
$value = get_term_meta( $result->id, $sd['tax_image_custom_field'], true );
if ( ( is_array($value) || is_object($value) ) ) {
if ( isset($value['url']) ) {
$value = $value['url'];
} elseif ( isset($value['guid']) ) {
$value = $value['guid'];
} elseif ( isset($value['id']) ) {
$value = $value['id'];
} elseif ( isset($value['ID']) ) {
$value = $value['ID'];
} elseif ( isset($value[0]) ) {
$value = $value[0];
}
}
if ( !empty($value) ) {
// Is this an image attachment ID
if ( is_numeric($value) ) {
$img = wp_get_attachment_image_src( intval($value) );
if ( isset($img[0]) ) {
$image = $img[0];
}
} else {
// Probably the image URL
$image = $value;
}
}
}
if ( !empty($image) ) {
if ( !$image_settings['image_cropping'] ) {
$result->image = $image;
} elseif ( strpos( $image, 'mshots/v1' ) === false ) {
$bfi_params = array(
'width' => $image_settings['image_width'],
'height' => $image_settings['image_height'],
'crop' => true,
);
if ( !$image_settings['image_transparency'] ) {
$bfi_params['color'] = wpdreams_rgb2hex( $image_settings['image_bg_color'] );
}
$result->image = asp_bfi_thumb( $image, $bfi_params );
} else {
$result->image = $image;
}
}
// Default, if defined and available
if ( empty($result->image) && !empty($sd['tax_image_default']) ) {
$result->image = $sd['tax_image_default'];
}
if ( !empty($result->image) ) {
$result->image = Str::fixSSLURLs($result->image);
}
}
}
/**
* Do this here, so the term image might exist.
* If you move this loop up, then the WooImage script might not work with isotope
*/
foreach ( $term_res as $k =>$v ) {
$v->title = wd_substr_at_word($v->title, $sd['tax_res_title_length']);
if ( $args['_ajax_search'] ) {
// If no image and defined, remove the result here, to perevent JS confusions
if ( isset($sd['resultstype']) && empty($v->image) &&
$sd['resultstype'] === 'isotopic' && $sd['i_ifnoimage'] === 'removeres'
) {
unset($term_res[ $k ]);
continue;
}
/* Same for polaroid mode */
if ( empty($v->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres'
) {
unset($term_res[ $k ]);
continue;
}
}
// ------------------------ CONTENT & CONTEXT --------------------------
// Get the words from around the search phrase, or just the description
$_content = Post::dealWithShortcodes($v->content, $sd['shortcode_op'] === 'remove');
$_content = Html::stripTags($_content, $sd['striptagsexclude']);
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $sd['descriptionlength'], $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $sd['descriptionlength'] ) ) {
$_content = wd_substr_at_word($_content, $sd['descriptionlength']);
}
$v->content = Str::fixSSLURLs( wd_closetags($_content) );
// ---------------------------------------------------------------------
$term_url = get_term_link( (int) $v->id, $v->taxonomy);
if ( $args['_wpml_lang'] !== '' ) {
$term_url = apply_filters( 'wpml_permalink', $term_url, $args['_wpml_lang'] );
}
// In case of unset taxonomy term
if ( !is_wp_error($term_url) ) {
$v->link = $term_url;
} else {
unset($term_res[ $k ]);
}
}
$this->results = $term_res;
}
}

View File

@@ -0,0 +1,802 @@
<?php
/**
* @noinspection DuplicatedCode
* @noinspection RegExpRedundantEscape
* @noinspection RegExp
*/
namespace WPDRMS\ASP\Search;
use WPDRMS\ASP\Utils\AdvancedField\AdvancedFieldParser;
use WPDRMS\ASP\Utils\Html;
use WPDRMS\ASP\Utils\MB;
use WPDRMS\ASP\Utils\Post;
use WPDRMS\ASP\Utils\Str;
use WPDRMS\ASP\Utils\User;
defined('ABSPATH') || die("You can't access this file directly.");
class SearchUsers extends SearchPostTypes {
protected function doSearch(): void {
global $wpdb;
$args = &$this->args;
$sd = $args['_sd'] ?? array();
// Prefixes and suffixes
$pre_field = $this->pre_field;
$suf_field = $this->suf_field;
$pre_like = $this->pre_like;
$suf_like = $this->suf_like;
$wcl = '%'; // Wildcard Left
$wcr = '%'; // Wildcard right
if ( $args['_exact_matches'] ) {
if ( $args['_exact_match_location'] === 'start' ) {
$wcl = '';
} elseif ( $args['_exact_match_location'] === 'end' ) {
$wcr = '';
} elseif ( $args['_exact_match_location'] === 'full' ) {
$wcr = '';
$wcl = '';
}
}
// Keyword logics
$kw_logic = $args['keyword_logic'];
$s = $this->s; // full keyword
$_s = $this->_s; // array of keywords
if ( $args['_limit'] > 0 ) {
$limit = $args['_limit'];
} elseif ( $args['_ajax_search'] ) {
$limit = $args['users_limit'];
} else {
$limit = $args['users_limit_override'];
}
if ( $limit <= 0 ) {
return;
}
$query_limit = $limit * $this->remaining_limit_mod;
$bp_cf_select = '';
$words = $args['_exact_matches'] && $s !== '' ? array( $s ) : $_s;
/**
* Ex.: When the minimum word count is 2, and the user enters 'a' then $_s is empty.
* But $s is not actually empty, thus the wrong query will be executed.
*/
if ( count($words) === 0 && $s !== '' ) {
$words = array( $s );
// Allow only beginnings
if ( !$args['_exact_matches'] ) {
$wcl = '';
}
}
if ( $s !== '' ) {
$words = !in_array($s, $words, true) ? array_merge(array( $s ), $words) : $words;
}
$relevance_added = false;
foreach ( $words as $k => $word ) {
$parts = array();
$relevance_parts = array();
$is_exact = $args['_exact_matches'] || ( count($words) > 1 && $k === 0 && ( $kw_logic === 'or' || $kw_logic === 'and' ) );
/*---------------------- Login Name query ------------------------*/
if ( $args['user_login_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->users . '.user_login' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->users . '.user_login' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
/*---------------------- Display Name query ------------------------*/
if ( $args['user_display_name_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->users . '.display_name' . $suf_field . " = '" . $word . "')";
}
if ( !$relevance_added ) {
if ( isset($_s[0]) ) {
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE '%" . $_s[0] . "%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE '$s%')
then " . ( w_isset_def($sd['titleweight'], 10) * 2 ) . ' else 0 end)';
$relevance_parts[] = '(case when
(' . $pre_field . $wpdb->users . '.display_name' . $suf_field . " LIKE '%$s%')
then " . w_isset_def($sd['titleweight'], 10) . ' else 0 end)';
}
}
/*---------------------------------------------------------------*/
/*---------------------- First Name query -----------------------*/
if ( $args['user_first_name_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = "( $wpdb->usermeta.meta_key = 'first_name' AND ( " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like ) )";
} else {
$parts[] = "( $wpdb->usermeta.meta_key = 'first_name' AND
(" . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " = '" . $word . "') )";
}
}
/*---------------------------------------------------------------*/
/*---------------------- Last Name query ------------------------*/
if ( $args['user_last_name_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = "( $wpdb->usermeta.meta_key = 'last_name' AND ( " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like ) )";
} else {
$parts[] = "( $wpdb->usermeta.meta_key = 'last_name' AND
(" . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " = '" . $word . "') )";
}
}
/*---------------------------------------------------------------*/
/*---------------------- Email query ------------------------*/
if ( $args['user_email_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = '( ' . $pre_field . $wpdb->users . '.user_email' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$parts[] = '
(' . $pre_field . $wpdb->users . '.user_email' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.user_email' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->users . '.user_email' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->users . '.user_email' . $suf_field . " = '" . $word . "')";
}
}
/*---------------------------------------------------------------*/
/*---------------------- Biography query ------------------------*/
if ( $args['user_bio_search'] ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$parts[] = "( $wpdb->usermeta.meta_key = 'description' AND ( " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like ) )";
} else {
$parts[] = "( $wpdb->usermeta.meta_key = 'description' AND
(" . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " = '" . $word . "') )";
}
}
/*---------------------------------------------------------------*/
/*-------------------- Other selected meta ----------------------*/
$args['user_search_meta_fields'] = !is_array($args['user_search_meta_fields']) ? array( $args['user_search_meta_fields'] ) : $args['user_search_meta_fields'];
if ( count( $args['user_search_meta_fields']) > 0 ) {
$cf_parts = array();
foreach ( $args['user_search_meta_fields'] as $cfield ) {
$key_part = "$wpdb->usermeta.meta_key='$cfield' AND ";
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$cf_parts[] = "( $key_part " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$cf_parts[] = "( $key_part
(" . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $wpdb->usermeta . '.meta_value' . $suf_field . " = '" . $word . "') )";
}
}
$parts[] = "( EXISTS (SELECT 1 FROM $wpdb->usermeta WHERE (" . implode(' OR ', $cf_parts) . ") AND $wpdb->users.ID = $wpdb->usermeta.user_id) )";
}
/*---------------------------------------------------------------*/
/*------------------ BP Xprofile field meta ---------------------*/
$args['user_search_bp_fields'] = !is_array($args['user_search_bp_fields']) ? array( $args['user_search_bp_fields'] ) : $args['user_search_bp_fields'];
$bp_meta_table = $wpdb->base_prefix . 'bp_xprofile_data';
if ( count($args['user_search_bp_fields']) > 0 && $wpdb->get_var("SHOW TABLES LIKE '$bp_meta_table'") === $bp_meta_table ) { // @phpcs:ignore
$bp_cf_parts = array();
foreach ( $args['user_search_bp_fields'] as $field_id ) {
$key_part = "$bp_meta_table.field_id = '" . $field_id . "' AND ";
if ( $kw_logic === 'or' || $kw_logic === 'and' || $is_exact ) {
$bp_cf_parts[] = "( $key_part " . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'$wcl" . $word . "$wcr'$suf_like )";
} else {
$bp_cf_parts[] = "( $key_part
(" . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " = '" . $word . "') )";
}
}
$parts[] = "( EXISTS (SELECT 1 FROM $bp_meta_table WHERE (" . implode(' OR ', $bp_cf_parts) . ") AND $bp_meta_table.user_id = $wpdb->users.ID ) )";
}
$this->parts[] = array( $parts, $relevance_parts );
$relevance_added = true;
}
/*------------------ BP Xprofile field meta ---------------------*/
$args['user_search_bp_fields'] = !is_array($args['user_search_bp_fields']) ? array( $args['user_search_bp_fields'] ) : $args['user_search_bp_fields'];
$bp_meta_table = $wpdb->base_prefix . 'bp_xprofile_data';
$bp_cf_parts = array();
if ( count($args['user_search_bp_fields']) > 0 && $wpdb->get_var("SHOW TABLES LIKE '$bp_meta_table'") === $bp_meta_table ) { // @phpcs:ignore
foreach ( $args['user_search_bp_fields'] as $field_id ) {
if ( $kw_logic === 'or' || $kw_logic === 'and' ) {
$op = strtoupper($kw_logic);
if ( count($_s) > 0 ) {
$_like = implode("%'$suf_like " . $op . ' ' . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'%", $words);
} else {
$_like = $s;
}
$bp_cf_parts[] = "( $bp_meta_table.field_id = " . $field_id . ' AND ( ' . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'$wcl" . $_like . "$wcr'$suf_like ) )";
} else {
$_like = array();
$op = $kw_logic === 'andex' ? 'AND' : 'OR';
foreach ( $words as $word ) {
$_like[] = '
(' . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'% " . $word . " %'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'" . $word . " %'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " LIKE $pre_like'% " . $word . "'$suf_like
OR " . $pre_field . $bp_meta_table . '.value' . $suf_field . " = '" . $word . "')";
}
$bp_cf_parts[] = "( $bp_meta_table.field_id = " . $field_id . ' AND (' . implode(' ' . $op . ' ', $_like) . ') )';
}
}
$parts[] = "( EXISTS (SELECT 1 FROM $bp_meta_table WHERE (" . implode(' OR ', $bp_cf_parts) . ") AND $bp_meta_table.user_id = $wpdb->users.ID ) )";
$this->parts[] = array( $parts, array() );
}
/*---------------------------------------------------------------*/
/*------------------------ Exclude Roles ------------------------*/
$roles_query = '';
$args['user_search_exclude_roles'] = !is_array($args['user_search_exclude_roles']) ? array( $args['user_search_exclude_roles'] ) : $args['user_search_exclude_roles'];
if ( count($args['user_search_exclude_roles']) > 0 ) {
$role_parts = array();
foreach ( $args['user_search_exclude_roles'] as $role ) {
$role_parts[] = $wpdb->usermeta . '.meta_value LIKE \'%"' . $role . '"%\'';
}
// Capabilities meta field is prefixed with the DB prefix
$roles_query = "AND $wpdb->users.ID NOT IN (
SELECT DISTINCT($wpdb->usermeta.user_id)
FROM $wpdb->usermeta
WHERE $wpdb->usermeta.meta_key='" . $wpdb->base_prefix . "capabilities' AND (" . implode(' OR ', $role_parts) . ')
)';
}
/*---------------------------------------------------------------*/
/*------------- Custom Fields with Custom selectors -------------*/
$cf_select = $this->buildCffQuery( $wpdb->users . '.ID' );
/*---------------------------------------------------------------*/
/*------------- Exclude and Include Users by ID -----------------*/
$exclude_query = '';
if ( count($args['user_search_exclude_ids']) > 0 ) {
$exclude_query .= " AND $wpdb->users.ID NOT IN(" . implode(',', $args['user_search_exclude_ids']) . ') ';
}
$include_query = '';
if ( count($args['user_search_include_ids']) ) {
$include_query .= " AND $wpdb->users.ID IN(" . implode(',', $args['user_search_include_ids']) . ') ';
}
/*---------------------------------------------------------------*/
/*----------------------- Title Field ---------------------------*/
switch ( w_isset_def($sd['user_search_title_field'], 'display_name') ) {
case 'login':
$uname_select = "$wpdb->users.user_login";
break;
default:
$uname_select = "$wpdb->users.display_name";
break;
}
/*---------------------------------------------------------------*/
/*-------------- Additional Query parts by Filters --------------*/
/**
* Use these filters to add additional parts to the select, join or where
* parts of the search query.
*/
$add_select = apply_filters('asp_user_query_add_select', '', $args, $s, $_s);
$add_join = apply_filters('asp_user_query_add_join', '', $args, $s, $_s);
$add_where = apply_filters('asp_user_query_add_where', '', $args, $s, $_s);
/*---------------------------------------------------------------*/
/*---------------- Primary custom field ordering ----------------*/
$custom_field_selectp = '1 ';
if (
strpos($args['user_primary_order'], 'customfp') !== false &&
$args['_user_primary_order_metakey'] !== false
) {
// @phpstan-ignore-next-line
$custom_field_selectp = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->usermeta
WHERE
$wpdb->usermeta.meta_key='" . esc_sql($args['_user_primary_order_metakey']) . "' AND
$wpdb->usermeta.user_id=$wpdb->users.ID
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
/*--------------- Secondary custom field ordering ---------------*/
$custom_field_selects = '1 ';
if (
strpos($args['user_secondary_order'], 'customfs') !== false &&
$args['_user_secondary_order_metakey'] !== false
) {
// @phpstan-ignore-next-line
$custom_field_selects = "(SELECT IF(meta_value IS NULL, 0, meta_value)
FROM $wpdb->usermeta
WHERE
$wpdb->usermeta.meta_key='" . esc_sql($args['_user_secondary_order_metakey']) . "' AND
$wpdb->usermeta.user_id=$wpdb->users.ID
LIMIT 1
) ";
}
/*---------------------------------------------------------------*/
$orderby_primary = $args['user_primary_order'];
$orderby_secondary = $args['user_secondary_order'];
if ( $args['user_primary_order_metatype'] === 'numeric' ) {
$orderby_primary = str_replace('customfp', 'CAST(customfp as SIGNED)', $orderby_primary);
}
if ( $args['user_secondary_order_metatype'] === 'numeric' ) {
$orderby_secondary = str_replace('customfs', 'CAST(customfs as SIGNED)', $orderby_secondary);
}
$this->query = "
SELECT
$add_select
{args_fields}
$wpdb->users.ID as id,
$this->c_blogid as `blogid`,
$uname_select as `title`,
$wpdb->users.user_registered as `date`,
'' as `author`,
'' as `content`,
'user' as `content_type`,
'users' as `g_content_type`,
{relevance_query} as `relevance`,
$wpdb->users.user_login as `user_login`,
$wpdb->users.user_nicename as `user_nicename`,
$wpdb->users.display_name as `user_display_name`,
$custom_field_selectp as `customfp`,
$custom_field_selects as `customfs`
FROM
$wpdb->users
LEFT JOIN $wpdb->usermeta ON $wpdb->usermeta.user_id = $wpdb->users.ID
$add_join
{args_join}
WHERE
(
{like_query}
$bp_cf_select
)
$add_where
$roles_query
AND $cf_select
$exclude_query
$include_query
{args_where}
GROUP BY
{args_groupby}
ORDER BY {args_orderby} $orderby_primary, $orderby_secondary, id DESC
LIMIT $query_limit";
// Place the argument query fields
if ( isset($args['user_query']) && is_array($args['user_query']) ) {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
array( $args['user_query']['fields'], $args['user_query']['join'], $args['user_query']['where'], $args['user_query']['orderby'] ),
$this->query
);
} else {
$this->query = str_replace(
array( '{args_fields}', '{args_join}', '{args_where}', '{args_orderby}' ),
'',
$this->query
);
}
if ( isset($args['user_query']['groupby']) && $args['user_query']['groupby'] !== '' ) {
$this->query = str_replace('{args_groupby}', $args['user_query']['groupby'], $this->query);
} else {
$this->query = str_replace('{args_groupby}', 'id', $this->query);
}
$querystr = $this->buildQuery( $this->parts );
$querystr = apply_filters('asp_query_users', $querystr, $args, $args['_id'], $args['_ajax_search']);
$userresults = $wpdb->get_results($querystr); // @phpcs:ignore
$this->results_count = count($userresults);
if ( !$args['_ajax_search'] && $this->results_count > $limit ) {
$this->results_count = $limit;
}
$userresults = array_slice($userresults, $args['_call_num'] * $limit, $limit);
$this->results = $userresults;
$this->return_count = count($this->results);
}
/**
* @param string $post_id_field
* @return string
* @noinspection PhpDuplicateSwitchCaseBodyInspection
*/
protected function buildCffQuery( string $post_id_field ): string {
global $wpdb;
$args = $this->args;
$parts = array();
$post_meta_allow_missing = $args['post_meta_allow_missing'];
foreach ( $args['user_meta_filter'] as $data ) {
$operator = $data['operator'];
$posted = $data['value'];
$field = $data['key'];
// Is this a special case of date operator?
if ( strpos($operator, 'datetime') === 0 ) {
switch ( $operator ) {
case 'datetime =':
$current_part = "($wpdb->usermeta.meta_value BETWEEN '$posted 00:00:00' AND '$posted 23:59:59')";
break;
case 'datetime <>':
$current_part = "($wpdb->usermeta.meta_value NOT BETWEEN '$posted 00:00:00' AND '$posted 23:59:59')";
break;
case 'datetime <':
$current_part = "($wpdb->usermeta.meta_value < '$posted 00:00:00')";
break;
case 'datetime <=':
$current_part = "($wpdb->usermeta.meta_value <= '$posted 23:59:59')";
break;
case 'datetime >':
$current_part = "($wpdb->usermeta.meta_value > '$posted 23:59:59')";
break;
case 'datetime >=':
$current_part = "($wpdb->usermeta.meta_value >= '$posted 00:00:00')";
break;
default:
$current_part = "($wpdb->usermeta.meta_value < '$posted 00:00:00')";
break;
}
// Is this a special case of timestamp?
} elseif ( strpos($operator, 'timestamp') === 0 ) {
switch ( $operator ) {
case 'timestamp =':
$current_part = "($wpdb->usermeta.meta_value BETWEEN $posted AND " . ( $posted + 86399 ) . ')';
break;
case 'timestamp <>':
$current_part = "($wpdb->usermeta.meta_value NOT BETWEEN $posted AND " . ( $posted + 86399 ) . ')';
break;
case 'timestamp <':
$current_part = "($wpdb->usermeta.meta_value < $posted)";
break;
case 'timestamp <=':
$current_part = "($wpdb->usermeta.meta_value <= " . ( $posted + 86399 ) . ')';
break;
case 'timestamp >':
$current_part = "($wpdb->usermeta.meta_value > " . ( $posted + 86399 ) . ')';
break;
case 'timestamp >=':
$current_part = "($wpdb->usermeta.meta_value >= $posted)";
break;
default:
$current_part = "($wpdb->usermeta.meta_value < $posted)";
break;
}
// Check BETWEEN first -> range slider
} elseif ( $operator === 'BETWEEN' ) {
$current_part = "($wpdb->usermeta.meta_value BETWEEN " . $posted[0] . ' AND ' . $posted[1] . ' )';
// If not BETWEEN but value is array, then drop-down or checkboxes
} elseif ( is_array($posted) ) {
// Is there a logic sent?
$logic = $data['logic'] ?? 'OR';
$values = '';
if ( $operator === 'IN' ) {
$val = implode("','", $posted);
if ( !empty($val) ) {
$values .= "$wpdb->usermeta.meta_value $operator ('" . $val . "')";
}
} else {
foreach ( $posted as $v ) {
if ( $operator === 'ELIKE' || $operator === 'NOT ELIKE' ) {
$_op = $operator === 'ELIKE' ? 'LIKE' : 'NOT LIKE';
if ( $values !== '' ) {
$values .= " $logic $wpdb->usermeta.meta_value $_op '" . $v . "'";
} else {
$values .= "$wpdb->usermeta.meta_value $_op '" . $v . "'";
}
} elseif ( $operator === 'NOT LIKE' || $operator === 'LIKE' ) {
if ( $values !== '' ) {
$values .= " $logic $wpdb->usermeta.meta_value $operator '%" . $v . "%'";
} else {
$values .= "$wpdb->usermeta.meta_value $operator '%" . $v . "%'";
}
} elseif ( $values !== '' ) {
$values .= " $logic $wpdb->usermeta.meta_value $operator " . $v;
} else {
$values .= "$wpdb->usermeta.meta_value $operator " . $v;
}
}
}
$values = $values === '' ? '0' : $values;
$current_part = "($values)";
// String operations
} elseif ( $operator === 'NOT LIKE' || $operator === 'LIKE' ) {
$current_part = "($wpdb->usermeta.meta_value $operator '%" . $posted . "%')";
} elseif ( $operator === 'ELIKE' || $operator === 'NOT ELIKE' ) {
$_op = $operator === 'ELIKE' ? 'LIKE' : 'NOT LIKE';
$current_part = "($wpdb->usermeta.meta_value $_op '$posted')";
// Numeric operations or problematic stuff left
} else {
$current_part = "($wpdb->usermeta.meta_value $operator $posted )";
}
// Finally, add the current part to the parts array
if ( $current_part !== '' ) {
$allowance = $data['allow_missing'] ?? $post_meta_allow_missing;
$parts[] = array( $field, $current_part, $allowance );
}
}
// The correct count is the unique fields count
// $meta_count = count( $unique_fields );
$cf_select = '(1)';
$cf_select_arr = array();
/**
* NOTE 1:
* With the previous NOT EXISTS(...) subquery solution the search would hang in some cases
* when checking if empty values are allowed. No idea why though...
* Eventually using separate sub-queries for each field is the best.
*
* NOTE 2:
* COUNT(post_id) is a MUST in the nested IF() statement !! Otherwise, the query will return empty rows, no idea why either
*/
foreach ( $parts as $part ) {
$field = $part[0]; // Field name
$def = $part[2] ? "(
SELECT IF((meta_key IS NULL OR meta_value = ''), -1, COUNT(umeta_id))
FROM $wpdb->usermeta
WHERE $wpdb->usermeta.user_id = $post_id_field AND $wpdb->usermeta.meta_key='$field'
LIMIT 1
) = -1
OR" : ''; // Allowance
$qry = $part[1]; // Query condition
$cf_select_arr[] = "
(
$def
(
SELECT COUNT(umeta_id) as mtc
FROM $wpdb->usermeta
WHERE $wpdb->usermeta.user_id = $post_id_field AND $wpdb->usermeta.meta_key='$field' AND $qry
GROUP BY umeta_id
ORDER BY mtc
LIMIT 1
) >= 1
)";
}
if ( count($cf_select_arr) ) {
// Connect them based on the meta logic
$cf_select = '( ' . implode( $args['post_meta_filter_logic'], $cf_select_arr ) . ' )';
}
return $cf_select;
}
/** @noinspection PhpUndefinedFunctionInspection */
protected function postProcess(): void {
$userresults = $this->results;
$s = $this->s;
$_s = $this->_s;
$args = &$this->args;
if ( !isset($args['_sd']) ) {
return;
}
$sd = $args['_sd'];
$com_options = wd_asp()->o['asp_compatibility'];
foreach ( $userresults as $k => &$r ) {
if ( $args['_ajax_search'] ) {
// If no image and defined, remove the result here, to perevent JS confusions
if ( empty($r->image) && $sd['resultstype'] === 'isotopic' && $sd['i_ifnoimage'] === 'removeres' ) {
unset($userresults[ $k ]);
continue;
}
/* Same for polaroid mode */
if ( empty($r->image) && isset($sd['resultstype']) &&
$sd['resultstype'] === 'polaroid' && $sd['pifnoimage'] === 'removeres'
) {
unset($userresults[ $k ]);
continue;
}
}
/*--------------------------- Link ------------------------------*/
switch ( $sd['user_search_url_source'] ) {
case 'bp_profile':
if ( function_exists('bp_core_get_user_domain') ) {
$r->link = bp_core_get_user_domain($r->id);
} else {
$r->link = get_author_posts_url($r->id);
}
break;
case 'custom':
$r->link = function_exists('pll_home_url') ? @pll_home_url() : home_url('/'); // @phpcs:ignore
$r->link .= str_replace(
array( '{USER_ID}', '{USER_LOGIN}', '{USER_NICENAME}', '{USER_DISPLAYNAME}' ),
array( $r->id, $r->user_login, $r->user_nicename, $r->user_display_name ),
$sd['user_search_custom_url']
);
if ( strpos($r->link, '{USER_NICKNAME}') !== false ) {
$r->link = str_replace('{USER_NICKNAME}', get_user_meta( $r->id, 'nickname', true ), $r->link);
}
break;
default:
$r->link = get_author_posts_url($r->id);
}
/*---------------------------------------------------------------*/
/*-------------------------- Image ------------------------------*/
if ( $sd['user_search_display_images'] ) {
if ( $sd['user_search_image_source'] === 'buddypress' &&
function_exists('bp_core_fetch_avatar')
) {
$im = bp_core_fetch_avatar(
array(
'item_id' => $r->id,
'html' => false,
'width' => intval($sd['user_image_width']),
'height' => intval($sd['user_image_height']),
)
);
} else {
$im = get_avatar_url(
$r->id,
array(
'size' => intval($sd['user_image_width']),
)
);
}
$image_settings = $sd['image_options'];
if ( !empty($im) ) {
$r->image = $im;
if ( !$image_settings['image_cropping'] ) {
$r->image = $im;
} elseif ( strpos( $im, 'mshots/v1' ) === false && strpos( $im, '.gif' ) === false ) {
$bfi_params = array(
'width' => $image_settings['image_width'],
'height' => $image_settings['image_height'],
'crop' => true,
);
if ( !$image_settings['image_transparency'] ) {
$bfi_params['color'] = wpdreams_rgb2hex( $image_settings['image_bg_color'] );
}
$r->image = asp_bfi_thumb( $im, $bfi_params );
} else {
$r->image = $im;
}
}
// Default, if defined and available
if ( empty($r->image) && !empty($sd['user_image_default']) ) {
$r->image = $sd['user_image_default'];
}
}
/*---------------------------------------------------------------*/
if ( !empty($sd['user_search_advanced_title_field']) ) {
$r->title = AdvancedFieldParser::instance()->parse($sd['user_search_advanced_title_field'], $r);
}
$r->title = wd_substr_at_word($r->title, $sd['user_res_title_length']);
/*---------------------- Description ----------------------------*/
switch ( $sd['user_search_description_field'] ) {
case 'buddypress_last_activity':
$update = get_user_meta($r->id, 'bp_latest_update', true);
if ( is_array($update) && isset($update['content']) ) {
$r->content = $update['content'];
}
break;
case 'nothing':
$r->content = '';
break;
default:
$content = get_user_meta($r->id, 'description', true);
if ( $content !== '' ) {
$r->content = $content;
}
}
$_content = Html::stripTags($r->content, $sd['striptagsexclude']);
$description_length = $sd['user_res_descriptionlength'];
// Get the words from around the search phrase, or just the description
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$_content = Str::getContext($_content, $description_length, $sd['description_context_depth'], $s, $_s);
} elseif ( $_content !== '' && ( MB::strlen( $_content ) > $description_length ) ) {
$_content = wd_substr_at_word($_content, $description_length);
}
$r->content = $_content;
if ( !empty($sd['user_search_advanced_description_field']) ) {
$cb = function ( $value, $field, $results, $field_args ) use ( $description_length, $sd, $s, $_s ) {
if ( strpos($field, 'html') !== false || ( isset($field_args['html']) && $field_args['html'] ) ) {
return $value;
}
$value = Post::dealWithShortcodes($value, $sd['shortcode_op'] === 'remove');
$strip_tags = $field_args['strip_tags'] ?? 1;
if ( !$strip_tags ) {
return $value;
}
$value = Html::stripTags($value, $sd['striptagsexclude']);
if ( $sd['description_context'] && count( $_s ) > 0 && $s !== '' ) {
$value = Str::getContext($value, $description_length, $sd['description_context_depth'], $s, $_s);
} elseif ( $value !== '' && ( MB::strlen( $value ) > $description_length ) ) {
$value = wd_substr_at_word($value, $description_length);
}
return $value;
};
add_filter('asp_user_advanced_field_value', $cb, 10, 4);
$r->content = AdvancedFieldParser::instance()->parse($sd['user_search_advanced_description_field'], $r);
remove_filter('asp_user_advanced_field_value', $cb);
}
$r->content = wd_closetags( $r->content );
/*---------------------------------------------------------------*/
// --------------------------------- DATE -----------------------------------
if ( $sd['showdate'] ) {
$post_time = strtotime($r->date);
if ( $sd['custom_date'] ) {
$date_format = w_isset_def($sd['custom_date_format'], 'Y-m-d H:i:s');
} else {
$date_format = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i:s');
}
$r->date = @date_i18n($date_format, $post_time); // @phpcs:ignore
}
// --------------------------------------------------------------------------
}
$this->results = $userresults;
}
}