Go to the documentation of this file.
41 protected $limits = [ 20, 50, 100, 250, 500 ];
44 parent::__construct(
'Whatlinkshere' );
71 if ( $par !==
null ) {
79 if ( !$this->target ) {
87 $this->
getSkin()->setRelevantTitle( $this->target );
89 $this->selfTitle = $this->
getPageTitle( $this->target->getPrefixedDBkey() );
91 $out->setPageTitle( $this->
msg(
'whatlinkshere-title', $this->target->getPrefixedText() ) );
92 $out->addBacklinkSubtitle( $this->target );
113 $hidelinks = $this->opts->getValue(
'hidelinks' );
114 $hideredirs = $this->opts->getValue(
'hideredirs' );
115 $hidetrans = $this->opts->getValue(
'hidetrans' );
118 $fetchlinks = ( !$hidelinks || !$hideredirs );
122 $conds[
'pagelinks'] = [
126 $conds[
'templatelinks'] = [
130 $conds[
'imagelinks'] = [
134 $namespace = $this->opts->getValue(
'namespace' );
135 $invert = $this->opts->getValue(
'invert' );
136 $nsComparison = ( $invert ?
'!= ' :
'= ' ) .
$dbr->addQuotes( $namespace );
137 if ( is_int( $namespace ) ) {
138 $conds[
'pagelinks'][] =
"pl_from_namespace $nsComparison";
139 $conds[
'templatelinks'][] =
"tl_from_namespace $nsComparison";
140 $conds[
'imagelinks'][] =
"il_from_namespace $nsComparison";
144 $conds[
'templatelinks'][] =
"tl_from >= $from";
145 $conds[
'pagelinks'][] =
"pl_from >= $from";
146 $conds[
'imagelinks'][] =
"il_from >= $from";
150 $conds[
'pagelinks'][
'rd_from'] =
null;
151 } elseif ( $hidelinks ) {
152 $conds[
'pagelinks'][] =
'rd_from is NOT NULL';
155 $queryFunc =
function (
IDatabase $dbr, $table, $fromCol ) use (
159 $queryLimit = $limit + 1;
161 "rd_from = $fromCol",
163 'rd_interwiki = ' .
$dbr->addQuotes(
'' ) .
' OR rd_interwiki IS NULL'
167 $subQuery =
$dbr->buildSelectSubquery(
168 [ $table,
'redirect',
'page' ],
169 [ $fromCol,
'rd_from' ],
171 __CLASS__ .
'::showIndirectLinks',
173 [
'ORDER BY' => $fromCol,
'LIMIT' => 2 * $queryLimit,
'STRAIGHT_JOIN' ],
175 'page' => [
'JOIN',
"$fromCol = page_id" ],
176 'redirect' => [
'LEFT JOIN', $on ]
180 [
'page',
'temp_backlink_range' => $subQuery ],
181 [
'page_id',
'page_namespace',
'page_title',
'rd_from',
'page_is_redirect' ],
183 __CLASS__ .
'::showIndirectLinks',
184 [
'ORDER BY' =>
'page_id',
'LIMIT' => $queryLimit ],
185 [
'page' => [
'JOIN',
"$fromCol = page_id" ] ]
190 $plRes = $queryFunc(
$dbr,
'pagelinks',
'pl_from' );
194 $tlRes = $queryFunc(
$dbr,
'templatelinks',
'tl_from' );
197 if ( !$hideimages ) {
198 $ilRes = $queryFunc(
$dbr,
'imagelinks',
'il_from' );
201 if ( ( !$fetchlinks || !$plRes->numRows() )
202 && ( $hidetrans || !$tlRes->numRows() )
203 && ( $hideimages || !$ilRes->numRows() )
205 if ( $level == 0 && !$this->
including() ) {
209 if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) {
212 $msgKey = is_int( $namespace ) ?
'nolinkshere-ns' :
'nolinkshere';
217 $this->target->isRedirect() ? [
'redirect' =>
'no' ] : []
220 $errMsg = $this->
msg( $msgKey )
221 ->params( $this->target->getPrefixedText() )
224 $out->addHTML( $errMsg );
225 $out->setStatusCode( 404 );
236 foreach ( $plRes as $row ) {
237 $row->is_template = 0;
239 $rows[$row->page_id] = $row;
243 foreach ( $tlRes as $row ) {
244 $row->is_template = 1;
246 $rows[$row->page_id] = $row;
249 if ( !$hideimages ) {
250 foreach ( $ilRes as $row ) {
251 $row->is_template = 0;
253 $rows[$row->page_id] = $row;
259 $rows = array_values( $rows );
261 $numRows = count( $rows );
264 if ( $numRows > $limit ) {
267 $nextId = $rows[$limit]->page_id;
269 $rows = array_slice( $rows, 0, $limit );
279 foreach ( $rows as $row ) {
280 $lb->add( $row->page_namespace, $row->page_title );
284 if ( $level == 0 && !$this->
including() ) {
292 $this->target->isRedirect() ? [
'redirect' =>
'no' ] : []
295 $msg = $this->
msg(
'linkshere' )
296 ->params( $this->target->getPrefixedText() )
299 $out->addHTML( $msg );
301 $prevnext = $this->
getPrevNext( $prevId, $nextId );
302 $out->addHTML( $prevnext );
304 $out->addHTML( $this->
listStart( $level ) );
305 foreach ( $rows as $row ) {
308 if ( $row->rd_from && $level < 2 ) {
313 $this->
getConfig()->
get(
'MaxRedirectLinksRetrieved' )
321 $out->addHTML( $this->
listEnd() );
323 if ( $level == 0 && !$this->
including() ) {
324 $out->addHTML( $prevnext );
329 return Xml::openElement(
'ul', ( $level ? [] : [
'id' =>
'mw-whatlinkshere-list' ] ) );
335 # local message cache
336 static $msgcache =
null;
337 if ( $msgcache ===
null ) {
338 static $msgs = [
'isredirect',
'istemplate',
'semicolon-separator',
339 'whatlinkshere-links',
'isimage',
'editlink' ];
341 foreach ( $msgs as $msg ) {
342 $msgcache[$msg] = $this->
msg( $msg )->escaped();
346 if ( $row->rd_from ) {
347 $query = [
'redirect' =>
'no' ];
355 $row->page_is_redirect ? [
'class' =>
'mw-redirect' ] : [],
362 if ( $row->rd_from ) {
363 $props[] = $msgcache[
'isredirect'];
365 if ( $row->is_template ) {
366 $props[] = $msgcache[
'istemplate'];
368 if ( $row->is_image ) {
369 $props[] = $msgcache[
'isimage'];
374 if ( count( $props ) ) {
375 $propsText = $this->
msg(
'parentheses' )
376 ->rawParams( implode( $msgcache[
'semicolon-separator'], $props ) )->escaped();
379 # Space for utilities links, with a what-links-here link provided
380 $wlhLink = $this->
wlhLink( $nt, $msgcache[
'whatlinkshere-links'], $msgcache[
'editlink'] );
382 $this->
msg(
'parentheses' )->rawParams( $wlhLink )->escaped(),
383 'mw-whatlinkshere-tools'
388 Xml::tags(
'li',
null,
"$link $propsText $dirmark $wlh" ) .
"\n";
403 if ( $text !==
null ) {
420 MediaWikiServices::getInstance()
422 ->userHasRight( $this->
getUser(),
'edit' ) &&
426 if ( $editText !==
null ) {
434 [
'action' =>
'edit' ]
443 if ( $text !==
null ) {
456 $currentLimit = $this->opts->getValue(
'limit' );
457 $prev = $this->
msg(
'whatlinkshere-prev' )->numParams( $currentLimit )->escaped();
458 $next = $this->
msg(
'whatlinkshere-next' )->numParams( $currentLimit )->escaped();
460 $changed = $this->opts->getChangedValues();
461 unset( $changed[
'target'] );
463 if ( $prevId != 0 ) {
464 $overrides = [
'from' => $this->opts->getValue(
'back' ) ];
465 $prev = $this->
makeSelfLink( $prev, array_merge( $changed, $overrides ) );
467 if ( $nextId != 0 ) {
468 $overrides = [
'from' => $nextId,
'back' => $prevId ];
469 $next = $this->
makeSelfLink( $next, array_merge( $changed, $overrides ) );
474 foreach ( $this->limits as $limit ) {
475 $prettyLimit = htmlspecialchars(
$lang->formatNum( $limit ) );
476 $overrides = [
'limit' => $limit ];
477 $limitLinks[] = $this->
makeSelfLink( $prettyLimit, array_merge( $changed, $overrides ) );
480 $nums =
$lang->pipeList( $limitLinks );
482 return $this->
msg(
'viewprevnext' )->rawParams( $prev, $next, $nums )->escaped();
487 $this->opts->consumeValue(
'target' );
489 $this->opts->consumeValues( [
'back',
'from' ] );
492 $namespace = $this->opts->consumeValue(
'namespace' );
493 $nsinvert = $this->opts->consumeValue(
'invert' );
498 # Values that should not be forgotten
500 foreach ( $this->opts->getUnconsumedValues() as $name => $value ) {
506 # Target input (.mw-searchInput enables suggestions)
508 'mw-whatlinkshere-target', 40,
$target, [
'class' =>
'mw-searchInput' ] );
515 'selected' => $namespace,
517 'label' => $this->
msg(
'namespace' )->text(),
518 'in-user-lang' =>
true,
520 'name' =>
'namespace',
522 'class' =>
'namespaceselector',
528 $this->
msg(
'invert' )->text(),
532 [
'title' => $this->
msg(
'tooltip-whatlinkshere-invert' )->text() ]
552 $show = $this->
msg(
'show' )->escaped();
553 $hide = $this->
msg(
'hide' )->escaped();
555 $changed = $this->opts->getChangedValues();
556 unset( $changed[
'target'] );
559 $types = [
'hidetrans',
'hidelinks',
'hideredirs' ];
560 if ( $this->target->getNamespace() ==
NS_FILE ) {
561 $types[] =
'hideimages';
567 foreach ( $types as
$type ) {
568 $chosen = $this->opts->getValue(
$type );
569 $msg = $chosen ? $show : $hide;
570 $overrides = [
$type => !$chosen ];
571 $links[] = $this->
msg(
"whatlinkshere-{$type}" )->rawParams(
572 $this->
makeSelfLink( $msg, array_merge( $changed, $overrides ) ) )->escaped();
576 $this->
msg(
'whatlinkshere-filters' )->text(),
getPageTitle( $subpage=false)
Get a self-referential title object.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Marks HTML that shouldn't be escaped.
Class representing a list of titles The execute() method checks them all for existence and adds them ...
getOutput()
Get the OutputPage being used for this instance.
if(!isset( $args[0])) $lang
getPrefixedText()
Get the prefixed title with spaces.
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
getSkin()
Shortcut to get the skin being used for this instance.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Shortcut to construct an includable special page.
getLanguage()
Shortcut to get user's language.
static openElement( $element, $attribs=null)
This opens an XML element.
static fieldset( $legend=false, $content=false, $attribs=[])
Shortcut for creating fieldsets.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
prefixSearchString( $search, $limit, $offset)
Perform a regular substring search for prefixSearchSubpages.
static wrapClass( $text, $class, $tag='span', $attribs=[])
Shortcut to make a specific element with a class attribute.
getDBkey()
Get the main part with underscores.
getConfig()
Shortcut to get main config object.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
getNamespace()
Get the namespace index, i.e.
getPrevNext( $prevId, $nextId)
wlhLink(Title $target, $text, $editText)
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
showIndirectLinks( $level, $target, $limit, $from=0, $back=0)
Implements Special:Whatlinkshere.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getUser()
Shortcut to get the User executing this instance.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
static namespaceSelector(array $params=[], array $selectAttribs=[])
Build a drop-down box for selecting a namespace.
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
execute( $par)
Default execute method Checks user permissions.
getRequest()
Get the WebRequest being used for this instance.
makeSelfLink( $text, $query)
listItem( $row, $nt, $target, $notClose=false)
Represents a title within MediaWiki.
static closeElement( $element)
Shortcut to close an XML element.
getFilterPanel()
Create filter panel.
MediaWiki Linker LinkRenderer null $linkRenderer
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
static inputLabel( $label, $name, $id, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field with a label.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
including( $x=null)
Whether the special page is being evaluated via transclusion.
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.