MediaWiki  master
Skin.php
Go to the documentation of this file.
1 <?php
26 
38 abstract class Skin extends ContextSource {
42  protected $skinname = null;
43 
44  protected $mRelevantTitle = null;
45  protected $mRelevantUser = null;
46 
51  public $stylename = null;
52 
57  static function getSkinNames() {
58  return SkinFactory::getDefaultInstance()->getSkinNames();
59  }
60 
65  static function getSkinNameMessages() {
66  $messages = [];
67  foreach ( self::getSkinNames() as $skinKey => $skinName ) {
68  $messages[] = "skinname-$skinKey";
69  }
70  return $messages;
71  }
72 
80  public static function getAllowedSkins() {
81  global $wgSkipSkins;
82 
83  $allowedSkins = self::getSkinNames();
84 
85  foreach ( $wgSkipSkins as $skip ) {
86  unset( $allowedSkins[$skip] );
87  }
88 
89  return $allowedSkins;
90  }
91 
101  static function normalizeKey( $key ) {
103 
104  $skinNames = self::getSkinNames();
105 
106  // Make keys lowercase for case-insensitive matching.
107  $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
108  $key = strtolower( $key );
109  $defaultSkin = strtolower( $wgDefaultSkin );
110  $fallbackSkin = strtolower( $wgFallbackSkin );
111 
112  if ( $key == '' || $key == 'default' ) {
113  // Don't return the default immediately;
114  // in a misconfiguration we need to fall back.
115  $key = $defaultSkin;
116  }
117 
118  if ( isset( $skinNames[$key] ) ) {
119  return $key;
120  }
121 
122  // Older versions of the software used a numeric setting
123  // in the user preferences.
124  $fallback = [
125  0 => $defaultSkin,
126  2 => 'cologneblue'
127  ];
128 
129  if ( isset( $fallback[$key] ) ) {
130  $key = $fallback[$key];
131  }
132 
133  if ( isset( $skinNames[$key] ) ) {
134  return $key;
135  } elseif ( isset( $skinNames[$defaultSkin] ) ) {
136  return $defaultSkin;
137  } else {
138  return $fallbackSkin;
139  }
140  }
141 
146  public function __construct( $skinname = null ) {
147  if ( is_string( $skinname ) ) {
148  $this->skinname = $skinname;
149  }
150  }
151 
155  public function getSkinName() {
156  return $this->skinname;
157  }
158 
162  public function initPage( OutputPage $out ) {
163  $this->preloadExistence();
164  }
165 
176  public function getDefaultModules() {
177  $out = $this->getOutput();
178  $user = $this->getUser();
179 
180  // Modules declared in the $modules literal are loaded
181  // for ALL users, on ALL pages, in ALL skins.
182  // Keep this list as small as possible!
183  $modules = [
184  'styles' => [
185  // The 'styles' key sets render-blocking style modules
186  // Unlike other keys in $modules, this is an associative array
187  // where each key is its own group pointing to a list of modules
188  'core' => [
189  'mediawiki.legacy.shared',
190  'mediawiki.legacy.commonPrint',
191  ],
192  'content' => [],
193  'syndicate' => [],
194  ],
195  'core' => [
196  'site',
197  'mediawiki.page.startup',
198  ],
199  // modules that enhance the content in some way
200  'content' => [
201  'mediawiki.page.ready',
202  ],
203  // modules relating to search functionality
204  'search' => [
205  'mediawiki.searchSuggest',
206  ],
207  // modules relating to functionality relating to watching an article
208  'watch' => [],
209  // modules which relate to the current users preferences
210  'user' => [],
211  // modules relating to RSS/Atom Feeds
212  'syndicate' => [],
213  ];
214 
215  // Preload jquery.tablesorter for mediawiki.page.ready
216  if ( strpos( $out->getHTML(), 'sortable' ) !== false ) {
217  $modules['content'][] = 'jquery.tablesorter';
218  }
219 
220  // Preload jquery.makeCollapsible for mediawiki.page.ready
221  if ( strpos( $out->getHTML(), 'mw-collapsible' ) !== false ) {
222  $modules['content'][] = 'jquery.makeCollapsible';
223  $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
224  }
225 
226  // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
227  // on every page is deprecated. Express a dependency instead.
228  if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
229  $modules['styles']['content'][] = 'mediawiki.ui.button';
230  }
231 
232  if ( $out->isTOCEnabled() ) {
233  $modules['content'][] = 'mediawiki.toc';
234  $modules['styles']['content'][] = 'mediawiki.toc.styles';
235  }
236 
237  // Add various resources if required
238  if ( $user->isLoggedIn()
239  && $user->isAllowedAll( 'writeapi', 'viewmywatchlist', 'editmywatchlist' )
240  && $this->getRelevantTitle()->canExist()
241  ) {
242  $modules['watch'][] = 'mediawiki.page.watch.ajax';
243  }
244 
245  if ( $user->getBoolOption( 'editsectiononrightclick' ) ) {
246  $modules['user'][] = 'mediawiki.action.view.rightClickEdit';
247  }
248 
249  // Crazy edit-on-double-click stuff
250  if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) {
251  $modules['user'][] = 'mediawiki.action.view.dblClickEdit';
252  }
253 
254  if ( $out->isSyndicated() ) {
255  $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
256  }
257 
258  return $modules;
259  }
260 
264  protected function preloadExistence() {
265  $titles = [];
266 
267  // User/talk link
268  $user = $this->getUser();
269  if ( $user->isLoggedIn() ) {
270  $titles[] = $user->getUserPage();
271  $titles[] = $user->getTalkPage();
272  }
273 
274  // Check, if the page can hold some kind of content, otherwise do nothing
275  $title = $this->getRelevantTitle();
276  if ( $title->canExist() ) {
277  if ( $title->isTalkPage() ) {
278  $titles[] = $title->getSubjectPage();
279  } else {
280  $titles[] = $title->getTalkPage();
281  }
282  }
283 
284  // Footer links (used by SkinTemplate::prepareQuickTemplate)
285  foreach ( [
286  $this->footerLinkTitle( 'privacy', 'privacypage' ),
287  $this->footerLinkTitle( 'aboutsite', 'aboutpage' ),
288  $this->footerLinkTitle( 'disclaimers', 'disclaimerpage' ),
289  ] as $title ) {
290  if ( $title ) {
291  $titles[] = $title;
292  }
293  }
294 
295  Hooks::run( 'SkinPreloadExistence', [ &$titles, $this ] );
296 
297  if ( $titles ) {
298  $lb = new LinkBatch( $titles );
299  $lb->setCaller( __METHOD__ );
300  $lb->execute();
301  }
302  }
303 
309  public function getRevisionId() {
310  return $this->getOutput()->getRevisionId();
311  }
312 
318  public function isRevisionCurrent() {
319  $revID = $this->getRevisionId();
320  return $revID == 0 || $revID == $this->getTitle()->getLatestRevID();
321  }
322 
328  public function setRelevantTitle( $t ) {
329  $this->mRelevantTitle = $t;
330  }
331 
342  public function getRelevantTitle() {
343  return $this->mRelevantTitle ?? $this->getTitle();
344  }
345 
351  public function setRelevantUser( $u ) {
352  $this->mRelevantUser = $u;
353  }
354 
363  public function getRelevantUser() {
364  if ( isset( $this->mRelevantUser ) ) {
365  return $this->mRelevantUser;
366  }
367  $title = $this->getRelevantTitle();
368  if ( $title->hasSubjectNamespace( NS_USER ) ) {
369  $rootUser = $title->getRootText();
370  if ( User::isIP( $rootUser ) ) {
371  $this->mRelevantUser = User::newFromName( $rootUser, false );
372  } else {
373  $user = User::newFromName( $rootUser, false );
374 
375  if ( $user ) {
376  $user->load( User::READ_NORMAL );
377 
378  if ( $user->isLoggedIn() ) {
379  $this->mRelevantUser = $user;
380  }
381  }
382  }
383  return $this->mRelevantUser;
384  }
385  return null;
386  }
387 
392  abstract function outputPage( OutputPage $out = null );
393 
399  public static function makeVariablesScript( $data, $nonce = null ) {
400  if ( $data ) {
403  $nonce
404  );
405  }
406  return '';
407  }
408 
415  public static function getDynamicStylesheetQuery() {
416  return [
417  'action' => 'raw',
418  'ctype' => 'text/css',
419  ];
420  }
421 
428  public function setupSkinUserCss( OutputPage $out ) {
429  // Stub.
430  }
431 
437  function getPageClasses( $title ) {
438  $numeric = 'ns-' . $title->getNamespace();
439  $user = $this->getUser();
440 
441  if ( $title->isSpecialPage() ) {
442  $type = 'ns-special';
443  // T25315: provide a class based on the canonical special page name without subpages
444  list( $canonicalName ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
445  resolveAlias( $title->getDBkey() );
446  if ( $canonicalName ) {
447  $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
448  } else {
449  $type .= ' mw-invalidspecialpage';
450  }
451  } else {
452  if ( $title->isTalkPage() ) {
453  $type = 'ns-talk';
454  } else {
455  $type = 'ns-subject';
456  }
457  // T208315: add HTML class when the user can edit the page
458  if ( $title->quickUserCan( 'edit', $user ) ) {
459  $type .= ' mw-editable';
460  }
461  }
462 
463  $name = Sanitizer::escapeClass( 'page-' . $title->getPrefixedText() );
464  $root = Sanitizer::escapeClass( 'rootpage-' . $title->getRootTitle()->getPrefixedText() );
465 
466  return "$numeric $type $name $root";
467  }
468 
473  public function getHtmlElementAttributes() {
474  $lang = $this->getLanguage();
475  return [
476  'lang' => $lang->getHtmlCode(),
477  'dir' => $lang->getDir(),
478  'class' => 'client-nojs',
479  ];
480  }
481 
489  function addToBodyAttributes( $out, &$bodyAttrs ) {
490  // does nothing by default
491  }
492 
497  function getLogo() {
498  return $this->getConfig()->get( 'Logo' );
499  }
500 
510  public function shouldPreloadLogo() {
511  return false;
512  }
513 
517  function getCategoryLinks() {
518  $out = $this->getOutput();
519  $allCats = $out->getCategoryLinks();
520 
521  if ( $allCats === [] ) {
522  return '';
523  }
524 
525  $embed = "<li>";
526  $pop = "</li>";
527 
528  $s = '';
529  $colon = $this->msg( 'colon-separator' )->escaped();
530 
531  if ( !empty( $allCats['normal'] ) ) {
532  $t = $embed . implode( $pop . $embed, $allCats['normal'] ) . $pop;
533 
534  $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped();
535  $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
536  $title = Title::newFromText( $linkPage );
537  $link = $title ? Linker::link( $title, $msg ) : $msg;
538  $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
539  $link . $colon . '<ul>' . $t . '</ul></div>';
540  }
541 
542  # Hidden categories
543  if ( isset( $allCats['hidden'] ) ) {
544  if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) {
545  $class = ' mw-hidden-cats-user-shown';
546  } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) {
547  $class = ' mw-hidden-cats-ns-shown';
548  } else {
549  $class = ' mw-hidden-cats-hidden';
550  }
551 
552  $s .= "<div id=\"mw-hidden-catlinks\" class=\"mw-hidden-catlinks$class\">" .
553  $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
554  $colon . '<ul>' . $embed . implode( $pop . $embed, $allCats['hidden'] ) . $pop . '</ul>' .
555  '</div>';
556  }
557 
558  # optional 'dmoz-like' category browser. Will be shown under the list
559  # of categories an article belong to
560  if ( $this->getConfig()->get( 'UseCategoryBrowser' ) ) {
561  $s .= '<br /><hr />';
562 
563  # get a big array of the parents tree
564  $parenttree = $this->getTitle()->getParentCategoryTree();
565  # Skin object passed by reference cause it can not be
566  # accessed under the method subfunction drawCategoryBrowser
567  $tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree ) );
568  # Clean out bogus first entry and sort them
569  unset( $tempout[0] );
570  asort( $tempout );
571  # Output one per line
572  $s .= implode( "<br />\n", $tempout );
573  }
574 
575  return $s;
576  }
577 
583  function drawCategoryBrowser( $tree ) {
584  $return = '';
585 
586  foreach ( $tree as $element => $parent ) {
587  if ( empty( $parent ) ) {
588  # element start a new list
589  $return .= "\n";
590  } else {
591  # grab the others elements
592  $return .= $this->drawCategoryBrowser( $parent ) . ' &gt; ';
593  }
594 
595  # add our current element to the list
596  $eltitle = Title::newFromText( $element );
597  $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) );
598  }
599 
600  return $return;
601  }
602 
606  function getCategories() {
607  $out = $this->getOutput();
608  $catlinks = $this->getCategoryLinks();
609 
610  // Check what we're showing
611  $allCats = $out->getCategoryLinks();
612  $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) ||
613  $this->getTitle()->getNamespace() == NS_CATEGORY;
614 
615  $classes = [ 'catlinks' ];
616  if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
617  $classes[] = 'catlinks-allhidden';
618  }
619 
620  return Html::rawElement(
621  'div',
622  [ 'id' => 'catlinks', 'class' => $classes, 'data-mw' => 'interface' ],
623  $catlinks
624  );
625  }
626 
641  protected function afterContentHook() {
642  $data = '';
643 
644  if ( Hooks::run( 'SkinAfterContent', [ &$data, $this ] ) ) {
645  // adding just some spaces shouldn't toggle the output
646  // of the whole <div/>, so we use trim() here
647  if ( trim( $data ) != '' ) {
648  // Doing this here instead of in the skins to
649  // ensure that the div has the same ID in all
650  // skins
651  $data = "<div id='mw-data-after-content'>\n" .
652  "\t$data\n" .
653  "</div>\n";
654  }
655  } else {
656  wfDebug( "Hook SkinAfterContent changed output processing.\n" );
657  }
658 
659  return $data;
660  }
661 
667  protected function generateDebugHTML() {
668  return MWDebug::getHTMLDebugLog();
669  }
670 
676  function bottomScripts() {
677  // TODO and the suckage continues. This function is really just a wrapper around
678  // OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
679  // up at some point
680  $chunks = [ $this->getOutput()->getBottomScripts() ];
681 
682  // Keep the hook appendage separate to preserve WrappedString objects.
683  // This enables BaseTemplate::getTrail() to merge them where possible.
684  $extraHtml = '';
685  Hooks::run( 'SkinAfterBottomScripts', [ $this, &$extraHtml ] );
686  if ( $extraHtml !== '' ) {
687  $chunks[] = $extraHtml;
688  }
689  return WrappedString::join( "\n", $chunks );
690  }
691 
698  function printSource() {
699  $oldid = $this->getRevisionId();
700  if ( $oldid ) {
701  $canonicalUrl = $this->getTitle()->getCanonicalURL( 'oldid=' . $oldid );
702  $url = htmlspecialchars( wfExpandIRI( $canonicalUrl ) );
703  } else {
704  // oldid not available for non existing pages
705  $url = htmlspecialchars( wfExpandIRI( $this->getTitle()->getCanonicalURL() ) );
706  }
707 
708  return $this->msg( 'retrievedfrom' )
709  ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
710  ->parse();
711  }
712 
716  function getUndeleteLink() {
717  $action = $this->getRequest()->getVal( 'action', 'view' );
718  $title = $this->getTitle();
719 
720  if ( ( !$title->exists() || $action == 'history' ) &&
721  $title->quickUserCan( 'deletedhistory', $this->getUser() )
722  ) {
723  $n = $title->isDeleted();
724 
725  if ( $n ) {
726  if ( $this->getTitle()->quickUserCan( 'undelete', $this->getUser() ) ) {
727  $msg = 'thisisdeleted';
728  } else {
729  $msg = 'viewdeleted';
730  }
731 
732  return $this->msg( $msg )->rawParams(
734  SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ),
735  $this->msg( 'restorelink' )->numParams( $n )->escaped() )
736  )->escaped();
737  }
738  }
739 
740  return '';
741  }
742 
747  function subPageSubtitle( $out = null ) {
748  if ( $out === null ) {
749  $out = $this->getOutput();
750  }
751  $title = $out->getTitle();
752  $subpages = '';
753 
754  if ( !Hooks::run( 'SkinSubPageSubtitle', [ &$subpages, $this, $out ] ) ) {
755  return $subpages;
756  }
757 
758  if ( $out->isArticle() && MWNamespace::hasSubpages( $title->getNamespace() ) ) {
759  $ptext = $title->getPrefixedText();
760  if ( strpos( $ptext, '/' ) !== false ) {
761  $links = explode( '/', $ptext );
762  array_pop( $links );
763  $c = 0;
764  $growinglink = '';
765  $display = '';
766  $lang = $this->getLanguage();
767 
768  foreach ( $links as $link ) {
769  $growinglink .= $link;
770  $display .= $link;
771  $linkObj = Title::newFromText( $growinglink );
772 
773  if ( is_object( $linkObj ) && $linkObj->isKnown() ) {
774  $getlink = Linker::linkKnown(
775  $linkObj,
776  htmlspecialchars( $display )
777  );
778 
779  $c++;
780 
781  if ( $c > 1 ) {
782  $subpages .= $lang->getDirMarkEntity() . $this->msg( 'pipe-separator' )->escaped();
783  } else {
784  $subpages .= '&lt; ';
785  }
786 
787  $subpages .= $getlink;
788  $display = '';
789  } else {
790  $display .= '/';
791  }
792  $growinglink .= '/';
793  }
794  }
795  }
796 
797  return $subpages;
798  }
799 
803  function getSearchLink() {
805  return $searchPage->getLocalURL();
806  }
807 
811  function escapeSearchLink() {
812  return htmlspecialchars( $this->getSearchLink() );
813  }
814 
819  function getCopyright( $type = 'detect' ) {
820  if ( $type == 'detect' ) {
821  if ( !$this->isRevisionCurrent()
822  && !$this->msg( 'history_copyright' )->inContentLanguage()->isDisabled()
823  ) {
824  $type = 'history';
825  } else {
826  $type = 'normal';
827  }
828  }
829 
830  if ( $type == 'history' ) {
831  $msg = 'history_copyright';
832  } else {
833  $msg = 'copyright';
834  }
835 
836  $config = $this->getConfig();
837 
838  if ( $config->get( 'RightsPage' ) ) {
839  $title = Title::newFromText( $config->get( 'RightsPage' ) );
840  $link = Linker::linkKnown( $title, $config->get( 'RightsText' ) );
841  } elseif ( $config->get( 'RightsUrl' ) ) {
842  $link = Linker::makeExternalLink( $config->get( 'RightsUrl' ), $config->get( 'RightsText' ) );
843  } elseif ( $config->get( 'RightsText' ) ) {
844  $link = $config->get( 'RightsText' );
845  } else {
846  # Give up now
847  return '';
848  }
849 
850  // Allow for site and per-namespace customization of copyright notice.
851  // @todo Remove deprecated $forContent param from hook handlers and then remove here.
852  $forContent = true;
853 
854  Hooks::run(
855  'SkinCopyrightFooter',
856  [ $this->getTitle(), $type, &$msg, &$link, &$forContent ]
857  );
858 
859  return $this->msg( $msg )->rawParams( $link )->text();
860  }
861 
865  function getCopyrightIcon() {
866  $out = '';
867  $config = $this->getConfig();
868 
869  $footerIcons = $config->get( 'FooterIcons' );
870  if ( $footerIcons['copyright']['copyright'] ) {
871  $out = $footerIcons['copyright']['copyright'];
872  } elseif ( $config->get( 'RightsIcon' ) ) {
873  $icon = htmlspecialchars( $config->get( 'RightsIcon' ) );
874  $url = $config->get( 'RightsUrl' );
875 
876  if ( $url ) {
877  $out .= '<a href="' . htmlspecialchars( $url ) . '">';
878  }
879 
880  $text = htmlspecialchars( $config->get( 'RightsText' ) );
881  $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />";
882 
883  if ( $url ) {
884  $out .= '</a>';
885  }
886  }
887 
888  return $out;
889  }
890 
895  function getPoweredBy() {
896  $resourceBasePath = $this->getConfig()->get( 'ResourceBasePath' );
897  $url1 = htmlspecialchars(
898  "$resourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
899  );
900  $url1_5 = htmlspecialchars(
901  "$resourceBasePath/resources/assets/poweredby_mediawiki_132x47.png"
902  );
903  $url2 = htmlspecialchars(
904  "$resourceBasePath/resources/assets/poweredby_mediawiki_176x62.png"
905  );
906  $text = '<a href="//www.mediawiki.org/"><img src="' . $url1
907  . '" srcset="' . $url1_5 . ' 1.5x, ' . $url2 . ' 2x" '
908  . 'height="31" width="88" alt="Powered by MediaWiki" /></a>';
909  Hooks::run( 'SkinGetPoweredBy', [ &$text, $this ] );
910  return $text;
911  }
912 
918  protected function lastModified() {
919  $timestamp = $this->getOutput()->getRevisionTimestamp();
920 
921  # No cached timestamp, load it from the database
922  if ( $timestamp === null ) {
923  $timestamp = Revision::getTimestampFromId( $this->getTitle(), $this->getRevisionId() );
924  }
925 
926  if ( $timestamp ) {
927  $d = $this->getLanguage()->userDate( $timestamp, $this->getUser() );
928  $t = $this->getLanguage()->userTime( $timestamp, $this->getUser() );
929  $s = ' ' . $this->msg( 'lastmodifiedat', $d, $t )->parse();
930  } else {
931  $s = '';
932  }
933 
934  if ( MediaWikiServices::getInstance()->getDBLoadBalancer()->getLaggedReplicaMode() ) {
935  $s .= ' <strong>' . $this->msg( 'laggedslavemode' )->parse() . '</strong>';
936  }
937 
938  return $s;
939  }
940 
945  function logoText( $align = '' ) {
946  if ( $align != '' ) {
947  $a = " style='float: {$align};'";
948  } else {
949  $a = '';
950  }
951 
952  $mp = $this->msg( 'mainpage' )->escaped();
953  $mptitle = Title::newMainPage();
954  $url = ( is_object( $mptitle ) ? htmlspecialchars( $mptitle->getLocalURL() ) : '' );
955 
956  $logourl = $this->getLogo();
957  $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
958 
959  return $s;
960  }
961 
970  function makeFooterIcon( $icon, $withImage = 'withImage' ) {
971  if ( is_string( $icon ) ) {
972  $html = $icon;
973  } else { // Assuming array
974  $url = $icon["url"] ?? null;
975  unset( $icon["url"] );
976  if ( isset( $icon["src"] ) && $withImage === 'withImage' ) {
977  // do this the lazy way, just pass icon data as an attribute array
978  $html = Html::element( 'img', $icon );
979  } else {
980  $html = htmlspecialchars( $icon["alt"] );
981  }
982  if ( $url ) {
983  $html = Html::rawElement( 'a',
984  [ "href" => $url, "target" => $this->getConfig()->get( 'ExternalLinkTarget' ) ],
985  $html );
986  }
987  }
988  return $html;
989  }
990 
995  function mainPageLink() {
998  $this->msg( 'mainpage' )->escaped()
999  );
1000 
1001  return $s;
1002  }
1003 
1010  public function footerLink( $desc, $page ) {
1011  $title = $this->footerLinkTitle( $desc, $page );
1012  if ( !$title ) {
1013  return '';
1014  }
1015 
1016  return Linker::linkKnown(
1017  $title,
1018  $this->msg( $desc )->escaped()
1019  );
1020  }
1021 
1027  private function footerLinkTitle( $desc, $page ) {
1028  // If the link description has been set to "-" in the default language,
1029  if ( $this->msg( $desc )->inContentLanguage()->isDisabled() ) {
1030  // then it is disabled, for all languages.
1031  return null;
1032  }
1033  // Otherwise, we display the link for the user, described in their
1034  // language (which may or may not be the same as the default language),
1035  // but we make the link target be the one site-wide page.
1036  $title = Title::newFromText( $this->msg( $page )->inContentLanguage()->text() );
1037 
1038  return $title ?: null;
1039  }
1040 
1045  function privacyLink() {
1046  return $this->footerLink( 'privacy', 'privacypage' );
1047  }
1048 
1053  function aboutLink() {
1054  return $this->footerLink( 'aboutsite', 'aboutpage' );
1055  }
1056 
1061  function disclaimerLink() {
1062  return $this->footerLink( 'disclaimers', 'disclaimerpage' );
1063  }
1064 
1072  function editUrlOptions() {
1073  $options = [ 'action' => 'edit' ];
1074 
1075  if ( !$this->isRevisionCurrent() ) {
1076  $options['oldid'] = intval( $this->getRevisionId() );
1077  }
1078 
1079  return $options;
1080  }
1081 
1086  function showEmailUser( $id ) {
1087  if ( $id instanceof User ) {
1088  $targetUser = $id;
1089  } else {
1090  $targetUser = User::newFromId( $id );
1091  }
1092 
1093  # The sending user must have a confirmed email address and the receiving
1094  # user must accept emails from the sender.
1095  return $this->getUser()->canSendEmail()
1096  && SpecialEmailUser::validateTarget( $targetUser, $this->getUser() ) === '';
1097  }
1098 
1110  function getSkinStylePath( $name ) {
1111  if ( $this->stylename === null ) {
1112  $class = static::class;
1113  throw new MWException( "$class::\$stylename must be set to use getSkinStylePath()" );
1114  }
1115 
1116  return $this->getConfig()->get( 'StylePath' ) . "/{$this->stylename}/$name";
1117  }
1118 
1119  /* these are used extensively in SkinTemplate, but also some other places */
1120 
1125  static function makeMainPageUrl( $urlaction = '' ) {
1127  self::checkTitle( $title, '' );
1128 
1129  return $title->getLinkURL( $urlaction );
1130  }
1131 
1143  static function makeSpecialUrl( $name, $urlaction = '', $proto = null ) {
1145  if ( is_null( $proto ) ) {
1146  return $title->getLocalURL( $urlaction );
1147  } else {
1148  return $title->getFullURL( $urlaction, false, $proto );
1149  }
1150  }
1151 
1158  static function makeSpecialUrlSubpage( $name, $subpage, $urlaction = '' ) {
1159  $title = SpecialPage::getSafeTitleFor( $name, $subpage );
1160  return $title->getLocalURL( $urlaction );
1161  }
1162 
1168  static function makeI18nUrl( $name, $urlaction = '' ) {
1169  $title = Title::newFromText( wfMessage( $name )->inContentLanguage()->text() );
1170  self::checkTitle( $title, $name );
1171  return $title->getLocalURL( $urlaction );
1172  }
1173 
1179  static function makeUrl( $name, $urlaction = '' ) {
1181  self::checkTitle( $title, $name );
1182 
1183  return $title->getLocalURL( $urlaction );
1184  }
1185 
1192  static function makeInternalOrExternalUrl( $name ) {
1193  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $name ) ) {
1194  return $name;
1195  } else {
1196  return self::makeUrl( $name );
1197  }
1198  }
1199 
1207  static function makeNSUrl( $name, $urlaction = '', $namespace = NS_MAIN ) {
1208  $title = Title::makeTitleSafe( $namespace, $name );
1209  self::checkTitle( $title, $name );
1210 
1211  return $title->getLocalURL( $urlaction );
1212  }
1213 
1220  static function makeUrlDetails( $name, $urlaction = '' ) {
1222  self::checkTitle( $title, $name );
1223 
1224  return [
1225  'href' => $title->getLocalURL( $urlaction ),
1226  'exists' => $title->isKnown(),
1227  ];
1228  }
1229 
1236  static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1238  self::checkTitle( $title, $name );
1239 
1240  return [
1241  'href' => $title->getLocalURL( $urlaction ),
1242  'exists' => true
1243  ];
1244  }
1245 
1252  static function checkTitle( &$title, $name ) {
1253  if ( !is_object( $title ) ) {
1255  if ( !is_object( $title ) ) {
1256  $title = Title::newFromText( '--error: link target missing--' );
1257  }
1258  }
1259  }
1260 
1282  public function buildSidebar() {
1283  $callback = function ( $old = null, &$ttl = null ) {
1284  $bar = [];
1285  $this->addToSidebar( $bar, 'sidebar' );
1286  Hooks::run( 'SkinBuildSidebar', [ $this, &$bar ] );
1287  if ( MessageCache::singleton()->isDisabled() ) {
1288  $ttl = WANObjectCache::TTL_UNCACHEABLE; // bug T133069
1289  }
1290 
1291  return $bar;
1292  };
1293 
1294  $msgCache = MessageCache::singleton();
1295  $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1296  $config = $this->getConfig();
1297 
1298  $sidebar = $config->get( 'EnableSidebarCache' )
1299  ? $wanCache->getWithSetCallback(
1300  $wanCache->makeKey( 'sidebar', $this->getLanguage()->getCode() ),
1301  $config->get( 'SidebarCacheExpiry' ),
1302  $callback,
1303  [
1304  'checkKeys' => [
1305  // Unless there is both no exact $code override nor an i18n definition
1306  // in the software, the only MediaWiki page to check is for $code.
1307  $msgCache->getCheckKey( $this->getLanguage()->getCode() )
1308  ],
1309  'lockTSE' => 30
1310  ]
1311  )
1312  : $callback();
1313 
1314  // Apply post-processing to the cached value
1315  Hooks::run( 'SidebarBeforeOutput', [ $this, &$sidebar ] );
1316 
1317  return $sidebar;
1318  }
1319 
1329  public function addToSidebar( &$bar, $message ) {
1330  $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1331  }
1332 
1340  function addToSidebarPlain( &$bar, $text ) {
1341  $lines = explode( "\n", $text );
1342 
1343  $heading = '';
1344  $config = $this->getConfig();
1345  $messageTitle = $config->get( 'EnableSidebarCache' )
1346  ? Title::newMainPage() : $this->getTitle();
1347 
1348  foreach ( $lines as $line ) {
1349  if ( strpos( $line, '*' ) !== 0 ) {
1350  continue;
1351  }
1352  $line = rtrim( $line, "\r" ); // for Windows compat
1353 
1354  if ( strpos( $line, '**' ) !== 0 ) {
1355  $heading = trim( $line, '* ' );
1356  if ( !array_key_exists( $heading, $bar ) ) {
1357  $bar[$heading] = [];
1358  }
1359  } else {
1360  $line = trim( $line, '* ' );
1361 
1362  if ( strpos( $line, '|' ) !== false ) { // sanity check
1363  $line = MessageCache::singleton()->transform( $line, false, null, $messageTitle );
1364  $line = array_map( 'trim', explode( '|', $line, 2 ) );
1365  if ( count( $line ) !== 2 ) {
1366  // Second sanity check, could be hit by people doing
1367  // funky stuff with parserfuncs... (T35321)
1368  continue;
1369  }
1370 
1371  $extraAttribs = [];
1372 
1373  $msgLink = $this->msg( $line[0] )->title( $messageTitle )->inContentLanguage();
1374  if ( $msgLink->exists() ) {
1375  $link = $msgLink->text();
1376  if ( $link == '-' ) {
1377  continue;
1378  }
1379  } else {
1380  $link = $line[0];
1381  }
1382  $msgText = $this->msg( $line[1] )->title( $messageTitle );
1383  if ( $msgText->exists() ) {
1384  $text = $msgText->text();
1385  } else {
1386  $text = $line[1];
1387  }
1388 
1389  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $link ) ) {
1390  $href = $link;
1391 
1392  // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1393  if ( $config->get( 'NoFollowLinks' ) &&
1394  !wfMatchesDomainList( $href, $config->get( 'NoFollowDomainExceptions' ) )
1395  ) {
1396  $extraAttribs['rel'] = 'nofollow';
1397  }
1398 
1399  if ( $config->get( 'ExternalLinkTarget' ) ) {
1400  $extraAttribs['target'] = $config->get( 'ExternalLinkTarget' );
1401  }
1402  } else {
1404 
1405  if ( $title ) {
1406  $title = $title->fixSpecialName();
1407  $href = $title->getLinkURL();
1408  } else {
1409  $href = 'INVALID-TITLE';
1410  }
1411  }
1412 
1413  $bar[$heading][] = array_merge( [
1414  'text' => $text,
1415  'href' => $href,
1416  'id' => Sanitizer::escapeIdForAttribute( 'n-' . strtr( $line[1], ' ', '-' ) ),
1417  'active' => false,
1418  ], $extraAttribs );
1419  } else {
1420  continue;
1421  }
1422  }
1423  }
1424 
1425  return $bar;
1426  }
1427 
1433  function getNewtalks() {
1434  $newMessagesAlert = '';
1435  $user = $this->getUser();
1436  $newtalks = $user->getNewMessageLinks();
1437  $out = $this->getOutput();
1438 
1439  // Allow extensions to disable or modify the new messages alert
1440  if ( !Hooks::run( 'GetNewMessagesAlert', [ &$newMessagesAlert, $newtalks, $user, $out ] ) ) {
1441  return '';
1442  }
1443  if ( $newMessagesAlert ) {
1444  return $newMessagesAlert;
1445  }
1446 
1447  if ( count( $newtalks ) == 1 && WikiMap::isCurrentWikiId( $newtalks[0]['wiki'] ) ) {
1448  $uTalkTitle = $user->getTalkPage();
1449  $lastSeenRev = $newtalks[0]['rev'] ?? null;
1450  $nofAuthors = 0;
1451  if ( $lastSeenRev !== null ) {
1452  $plural = true; // Default if we have a last seen revision: if unknown, use plural
1453  $latestRev = Revision::newFromTitle( $uTalkTitle, false, Revision::READ_NORMAL );
1454  if ( $latestRev !== null ) {
1455  // Singular if only 1 unseen revision, plural if several unseen revisions.
1456  $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1457  $nofAuthors = $uTalkTitle->countAuthorsBetween(
1458  $lastSeenRev, $latestRev, 10, 'include_new' );
1459  }
1460  } else {
1461  // Singular if no revision -> diff link will show latest change only in any case
1462  $plural = false;
1463  }
1464  $plural = $plural ? 999 : 1;
1465  // 999 signifies "more than one revision". We don't know how many, and even if we did,
1466  // the number of revisions or authors is not necessarily the same as the number of
1467  // "messages".
1468  $newMessagesLink = Linker::linkKnown(
1469  $uTalkTitle,
1470  $this->msg( 'newmessageslinkplural' )->params( $plural )->escaped(),
1471  [],
1472  $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1473  );
1474 
1475  $newMessagesDiffLink = Linker::linkKnown(
1476  $uTalkTitle,
1477  $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->escaped(),
1478  [],
1479  $lastSeenRev !== null
1480  ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1481  : [ 'diff' => 'cur' ]
1482  );
1483 
1484  if ( $nofAuthors >= 1 && $nofAuthors <= 10 ) {
1485  $newMessagesAlert = $this->msg(
1486  'youhavenewmessagesfromusers',
1487  $newMessagesLink,
1488  $newMessagesDiffLink
1489  )->numParams( $nofAuthors, $plural );
1490  } else {
1491  // $nofAuthors === 11 signifies "11 or more" ("more than 10")
1492  $newMessagesAlert = $this->msg(
1493  $nofAuthors > 10 ? 'youhavenewmessagesmanyusers' : 'youhavenewmessages',
1494  $newMessagesLink,
1495  $newMessagesDiffLink
1496  )->numParams( $plural );
1497  }
1498  $newMessagesAlert = $newMessagesAlert->text();
1499  # Disable CDN cache
1500  $out->setCdnMaxage( 0 );
1501  } elseif ( count( $newtalks ) ) {
1502  $sep = $this->msg( 'newtalkseparator' )->escaped();
1503  $msgs = [];
1504 
1505  foreach ( $newtalks as $newtalk ) {
1506  $msgs[] = Xml::element(
1507  'a',
1508  [ 'href' => $newtalk['link'] ], $newtalk['wiki']
1509  );
1510  }
1511  $parts = implode( $sep, $msgs );
1512  $newMessagesAlert = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped();
1513  $out->setCdnMaxage( 0 );
1514  }
1515 
1516  return $newMessagesAlert;
1517  }
1518 
1526  private function getCachedNotice( $name ) {
1527  $config = $this->getConfig();
1528 
1529  if ( $name === 'default' ) {
1530  // special case
1531  $notice = $config->get( 'SiteNotice' );
1532  if ( empty( $notice ) ) {
1533  return false;
1534  }
1535  } else {
1536  $msg = $this->msg( $name )->inContentLanguage();
1537  if ( $msg->isBlank() ) {
1538  return '';
1539  } elseif ( $msg->isDisabled() ) {
1540  return false;
1541  }
1542  $notice = $msg->plain();
1543  }
1544 
1545  $services = MediaWikiServices::getInstance();
1546  $cache = $services->getMainWANObjectCache();
1547  $parsed = $cache->getWithSetCallback(
1548  // Use the extra hash appender to let eg SSL variants separately cache
1549  // Key is verified with md5 hash of unparsed wikitext
1550  $cache->makeKey( $name, $config->get( 'RenderHashAppend' ), md5( $notice ) ),
1551  // TTL in seconds
1552  600,
1553  function () use ( $notice ) {
1554  return $this->getOutput()->parseAsInterface( $notice );
1555  }
1556  );
1557 
1558  $contLang = $services->getContentLanguage();
1559  return Html::rawElement(
1560  'div',
1561  [
1562  'id' => 'localNotice',
1563  'lang' => $contLang->getHtmlCode(),
1564  'dir' => $contLang->getDir()
1565  ],
1566  $parsed
1567  );
1568  }
1569 
1575  function getSiteNotice() {
1576  $siteNotice = '';
1577 
1578  if ( Hooks::run( 'SiteNoticeBefore', [ &$siteNotice, $this ] ) ) {
1579  if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
1580  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1581  } else {
1582  $anonNotice = $this->getCachedNotice( 'anonnotice' );
1583  if ( $anonNotice === false ) {
1584  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1585  } else {
1586  $siteNotice = $anonNotice;
1587  }
1588  }
1589  if ( $siteNotice === false ) {
1590  $siteNotice = $this->getCachedNotice( 'default' );
1591  }
1592  }
1593 
1594  Hooks::run( 'SiteNoticeAfter', [ &$siteNotice, $this ] );
1595  return $siteNotice;
1596  }
1597 
1611  public function doEditSectionLink( Title $nt, $section, $tooltip, Language $lang ) {
1612  // HTML generated here should probably have userlangattributes
1613  // added to it for LTR text on RTL pages
1614 
1615  $attribs = [];
1616  if ( !is_null( $tooltip ) ) {
1617  $attribs['title'] = $this->msg( 'editsectionhint' )->rawParams( $tooltip )
1618  ->inLanguage( $lang )->text();
1619  }
1620 
1621  $links = [
1622  'editsection' => [
1623  'text' => $this->msg( 'editsection' )->inLanguage( $lang )->escaped(),
1624  'targetTitle' => $nt,
1625  'attribs' => $attribs,
1626  'query' => [ 'action' => 'edit', 'section' => $section ],
1627  'options' => [ 'noclasses', 'known' ]
1628  ]
1629  ];
1630 
1631  Hooks::run( 'SkinEditSectionLinks', [ $this, $nt, $section, $tooltip, &$links, $lang ] );
1632 
1633  $result = '<span class="mw-editsection"><span class="mw-editsection-bracket">[</span>';
1634 
1635  $linksHtml = [];
1636  foreach ( $links as $k => $linkDetails ) {
1637  $linksHtml[] = Linker::link(
1638  $linkDetails['targetTitle'],
1639  $linkDetails['text'],
1640  $linkDetails['attribs'],
1641  $linkDetails['query'],
1642  $linkDetails['options']
1643  );
1644  }
1645 
1646  $result .= implode(
1647  '<span class="mw-editsection-divider">'
1648  . $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
1649  . '</span>',
1650  $linksHtml
1651  );
1652 
1653  $result .= '<span class="mw-editsection-bracket">]</span></span>';
1654  return $result;
1655  }
1656 
1657 }
showEmailUser( $id)
Definition: Skin.php:1086
static makeUrlDetails( $name, $urlaction='')
these return an array with the &#39;href&#39; and boolean &#39;exists&#39;
Definition: Skin.php:1220
static makeI18nUrl( $name, $urlaction='')
Definition: Skin.php:1168
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method&#39;s arguments.
Definition: Skin.php:970
wfUrlProtocols( $includeProtocolRelative=true)
Returns a regular expression of url protocols.
lastModified()
Get the timestamp of the latest revision, formatted in user language.
Definition: Skin.php:918
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1982
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
footerLinkTitle( $desc, $page)
Definition: Skin.php:1027
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
static normalizeKey( $key)
Normalize a skin preference value to a form that can be loaded.
Definition: Skin.php:101
either a plain
Definition: hooks.txt:2043
static getTimestampFromId( $title, $id, $flags=0)
Get rev_timestamp from rev_id, without loading the rest of the row.
Definition: Revision.php:1264
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e...
Definition: Skin.php:641
setRelevantUser( $u)
Set the "relevant" user.
Definition: Skin.php:351
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:895
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1433
static validateTarget( $target, User $sender=null)
Validate target User.
const NS_MAIN
Definition: Defines.php:64
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1143
static newMainPage(MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition: Title.php:653
static isIP( $name)
Does the string match an anonymous IP address?
Definition: User.php:969
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition: Skin.php:1282
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
privacyLink()
Gets the link to the wiki&#39;s privacy policy page.
Definition: Skin.php:1045
if(!isset( $args[0])) $lang
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
doEditSectionLink(Title $nt, $section, $tooltip, Language $lang)
Create a section edit link.
Definition: Skin.php:1611
initPage(OutputPage $out)
Definition: Skin.php:162
editUrlOptions()
Return URL options for the &#39;edit page&#39; link.
Definition: Skin.php:1072
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
getLogo()
URL to the logo.
Definition: Skin.php:497
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:57
getCopyrightIcon()
Definition: Skin.php:865
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
static makeConfigSetScript(array $configuration)
Returns JS code which will set the MediaWiki configuration array to the given value.
msg( $key)
Get a Message object with context set Parameters are the same as wfMessage()
getCachedNotice( $name)
Get a cached notice.
Definition: Skin.php:1526
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that&#39;s attached to a given link target...
Definition: Revision.php:137
shouldPreloadLogo()
Whether the logo should be preloaded with an HTTP link header or not.
Definition: Skin.php:510
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
getCategories()
Definition: Skin.php:606
getSiteNotice()
Get the site notice.
Definition: Skin.php:1575
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area. ...
Definition: MWDebug.php:455
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1980
getPageClasses( $title)
TODO: document.
Definition: Skin.php:437
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:3050
addToBodyAttributes( $out, &$bodyAttrs)
This will be called by OutputPage::headElement when it is creating the "<body>" tag, skins can override it if they have a need to add in any body attributes or classes of their own.
Definition: Skin.php:489
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:48
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:780
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:34
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1982
preloadExistence()
Preload the existence of three commonly-requested pages in a single query.
Definition: Skin.php:264
footerLink( $desc, $page)
Returns an HTML link for use in the footer.
Definition: Skin.php:1010
$modules
wfMatchesDomainList( $url, $domains)
Check whether a given URL has a domain that occurs in a given set of domains.
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
$mRelevantTitle
Definition: Skin.php:44
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
Definition: hooks.txt:2217
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1252
the value of this variable comes from LanguageConverter indexed by page_id indexed by prefixed DB keys on which the links will be shown can modify can modify can modify this should be populated with an alert message to that effect $newtalks
Definition: hooks.txt:1676
mainPageLink()
Gets the link to the wiki&#39;s main page.
Definition: Skin.php:995
static escapeIdForAttribute( $id, $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
Definition: Sanitizer.php:1287
drawCategoryBrowser( $tree)
Render the array as a series of links.
Definition: Skin.php:583
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:342
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
subPageSubtitle( $out=null)
Definition: Skin.php:747
getCategoryLinks()
Definition: Skin.php:517
disclaimerLink()
Gets the link to the wiki&#39;s general disclaimers page.
Definition: Skin.php:1061
$cache
Definition: mcc.php:33
getSearchLink()
Definition: Skin.php:803
$mRelevantUser
Definition: Skin.php:45
const NS_CATEGORY
Definition: Defines.php:78
static makeVariablesScript( $data, $nonce=null)
Definition: Skin.php:399
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1982
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:846
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
Definition: hooks.txt:1982
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:667
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
setRelevantTitle( $t)
Set the "relevant" title.
Definition: Skin.php:328
getHtmlElementAttributes()
Return values for <html> element.
Definition: Skin.php:473
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1410
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:363
aboutLink()
Gets the link to the wiki&#39;s about page.
Definition: Skin.php:1053
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition: Skin.php:1340
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition: Skin.php:1329
outputPage(OutputPage $out=null)
Outputs the HTML generated by other functions.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:82
logoText( $align='')
Definition: Skin.php:945
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it&#39;s convenient to think so) ...
Definition: Skin.php:1236
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
static makeInlineScript( $script, $nonce=null)
Returns an HTML script tag that runs given JS code after startup and base modules.
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition: hooks.txt:3050
static makeUrl( $name, $urlaction='')
Definition: Skin.php:1179
getDefaultModules()
Defines the ResourceLoader modules that should be added to the skin It is recommended that skins wish...
Definition: Skin.php:176
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:617
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page...
Definition: Skin.php:698
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:611
string $stylename
Stylesheets set to use.
Definition: Skin.php:51
$fallback
Definition: MessagesAb.php:11
$lines
Definition: router.php:61
static isCurrentWikiId( $wikiId)
Definition: WikiMap.php:312
linkcache txt The LinkCache class maintains a list of article titles and the information about whether or not the article exists in the database This is used to mark up links when displaying a page If the same link appears more than once on any page then it only has to be looked up once In most cases link lookups are done in batches with the LinkBatch class or the equivalent in so the link cache is mostly useful for short snippets of parsed and for links in the navigation areas of the skin The link cache was formerly used to track links used in a document for the purposes of updating the link tables This application is now deprecated To create a you can use the following $titles
Definition: linkcache.txt:17
$parent
Definition: pageupdater.txt:71
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
wfExpandIRI( $url)
Take a URL, make sure it&#39;s expanded to fully qualified, and replace any encoded non-ASCII Unicode cha...
isRevisionCurrent()
Whether the revision displayed is the latest revision of the page.
Definition: Skin.php:318
static hasSubpages( $index)
Does the namespace allow subpages?
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to &#39;known&#39;.
Definition: Linker.php:146
$wgDefaultSkin
Default skin, for new users and anonymous visitors.
static makeNSUrl( $name, $urlaction='', $namespace=NS_MAIN)
this can be passed the NS number as defined in Language.php
Definition: Skin.php:1207
$wgSkipSkins
Specify the names of skins that should not be presented in the list of available skins in user prefer...
$line
Definition: cdb.php:59
static getSkinNameMessages()
Fetch the skinname messages for available skins.
Definition: Skin.php:65
getCopyright( $type='detect')
Definition: Skin.php:819
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
$wgFallbackSkin
Fallback skin used when the skin defined by $wgDefaultSkin can&#39;t be found.
getUndeleteLink()
Definition: Skin.php:716
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
$messages
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1192
getSkinStylePath( $name)
Return a fully resolved style path URL to images or styles stored in the current skin&#39;s folder...
Definition: Skin.php:1110
static getSafeTitleFor( $name, $subpage=false)
Get a localised Title object for a page name with a possibly unvalidated subpage. ...
static getDynamicStylesheetQuery()
Get the query to generate a dynamic stylesheet.
Definition: Skin.php:415
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:587
setupSkinUserCss(OutputPage $out)
Hook point for adding style modules to OutputPage.
Definition: Skin.php:428
static makeMainPageUrl( $urlaction='')
Definition: Skin.php:1125
$searchPage
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:84
getRevisionId()
Get the current revision ID.
Definition: Skin.php:309
escapeSearchLink()
Definition: Skin.php:811
getSkinName()
Definition: Skin.php:155
static getAllowedSkins()
Fetch the list of user-selectable skins in regards to $wgSkipSkins.
Definition: Skin.php:80
static getDefaultInstance()
Definition: SkinFactory.php:50
__construct( $skinname=null)
Definition: Skin.php:146
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:676
static singleton()
Get the signleton instance of this class.
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1473
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1158
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
string null $skinname
Definition: Skin.php:42
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:319