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  $config = $this->getConfig();
179  $user = $this->getUser();
180 
181  // Modules declared in the $modules literal are loaded
182  // for ALL users, on ALL pages, in ALL skins.
183  // Keep this list as small as possible!
184  $modules = [
185  'styles' => [
186  // The 'styles' key sets render-blocking style modules
187  // Unlike other keys in $modules, this is an associative array
188  // where each key is its own group pointing to a list of modules
189  'core' => [
190  'mediawiki.legacy.shared',
191  'mediawiki.legacy.commonPrint',
192  ],
193  'content' => [],
194  'syndicate' => [],
195  ],
196  'core' => [
197  'site',
198  'mediawiki.page.startup',
199  'mediawiki.user',
200  ],
201  // modules that enhance the content in some way
202  'content' => [
203  'mediawiki.page.ready',
204  ],
205  // modules relating to search functionality
206  'search' => [],
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  $modules['search'][] = 'mediawiki.searchSuggest';
246 
247  if ( $user->getBoolOption( 'editsectiononrightclick' ) ) {
248  $modules['user'][] = 'mediawiki.action.view.rightClickEdit';
249  }
250 
251  // Crazy edit-on-double-click stuff
252  if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) {
253  $modules['user'][] = 'mediawiki.action.view.dblClickEdit';
254  }
255 
256  if ( $out->isSyndicated() ) {
257  $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
258  }
259 
260  return $modules;
261  }
262 
266  protected function preloadExistence() {
267  $titles = [];
268 
269  // User/talk link
270  $user = $this->getUser();
271  if ( $user->isLoggedIn() ) {
272  $titles[] = $user->getUserPage();
273  $titles[] = $user->getTalkPage();
274  }
275 
276  // Check, if the page can hold some kind of content, otherwise do nothing
277  $title = $this->getRelevantTitle();
278  if ( $title->canExist() ) {
279  if ( $title->isTalkPage() ) {
280  $titles[] = $title->getSubjectPage();
281  } else {
282  $titles[] = $title->getTalkPage();
283  }
284  }
285 
286  // Footer links (used by SkinTemplate::prepareQuickTemplate)
287  foreach ( [
288  $this->footerLinkTitle( 'privacy', 'privacypage' ),
289  $this->footerLinkTitle( 'aboutsite', 'aboutpage' ),
290  $this->footerLinkTitle( 'disclaimers', 'disclaimerpage' ),
291  ] as $title ) {
292  if ( $title ) {
293  $titles[] = $title;
294  }
295  }
296 
297  Hooks::run( 'SkinPreloadExistence', [ &$titles, $this ] );
298 
299  if ( $titles ) {
300  $lb = new LinkBatch( $titles );
301  $lb->setCaller( __METHOD__ );
302  $lb->execute();
303  }
304  }
305 
311  public function getRevisionId() {
312  return $this->getOutput()->getRevisionId();
313  }
314 
320  public function isRevisionCurrent() {
321  $revID = $this->getRevisionId();
322  return $revID == 0 || $revID == $this->getTitle()->getLatestRevID();
323  }
324 
330  public function setRelevantTitle( $t ) {
331  $this->mRelevantTitle = $t;
332  }
333 
344  public function getRelevantTitle() {
345  if ( isset( $this->mRelevantTitle ) ) {
346  return $this->mRelevantTitle;
347  }
348  return $this->getTitle();
349  }
350 
356  public function setRelevantUser( $u ) {
357  $this->mRelevantUser = $u;
358  }
359 
368  public function getRelevantUser() {
369  if ( isset( $this->mRelevantUser ) ) {
370  return $this->mRelevantUser;
371  }
372  $title = $this->getRelevantTitle();
373  if ( $title->hasSubjectNamespace( NS_USER ) ) {
374  $rootUser = $title->getRootText();
375  if ( User::isIP( $rootUser ) ) {
376  $this->mRelevantUser = User::newFromName( $rootUser, false );
377  } else {
378  $user = User::newFromName( $rootUser, false );
379 
380  if ( $user ) {
381  $user->load( User::READ_NORMAL );
382 
383  if ( $user->isLoggedIn() ) {
384  $this->mRelevantUser = $user;
385  }
386  }
387  }
388  return $this->mRelevantUser;
389  }
390  return null;
391  }
392 
397  abstract function outputPage( OutputPage $out = null );
398 
404  public static function makeVariablesScript( $data, $nonce = null ) {
405  if ( $data ) {
408  $nonce
409  );
410  }
411  return '';
412  }
413 
420  public static function getDynamicStylesheetQuery() {
421  return [
422  'action' => 'raw',
423  'ctype' => 'text/css',
424  ];
425  }
426 
433  public function setupSkinUserCss( OutputPage $out ) {
434  // Stub.
435  }
436 
442  function getPageClasses( $title ) {
443  $numeric = 'ns-' . $title->getNamespace();
444 
445  if ( $title->isSpecialPage() ) {
446  $type = 'ns-special';
447  // T25315: provide a class based on the canonical special page name without subpages
448  list( $canonicalName ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
449  resolveAlias( $title->getDBkey() );
450  if ( $canonicalName ) {
451  $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
452  } else {
453  $type .= ' mw-invalidspecialpage';
454  }
455  } elseif ( $title->isTalkPage() ) {
456  $type = 'ns-talk';
457  } else {
458  $type = 'ns-subject';
459  }
460 
461  $name = Sanitizer::escapeClass( 'page-' . $title->getPrefixedText() );
462  $root = Sanitizer::escapeClass( 'rootpage-' . $title->getRootTitle()->getPrefixedText() );
463 
464  return "$numeric $type $name $root";
465  }
466 
471  public function getHtmlElementAttributes() {
472  $lang = $this->getLanguage();
473  return [
474  'lang' => $lang->getHtmlCode(),
475  'dir' => $lang->getDir(),
476  'class' => 'client-nojs',
477  ];
478  }
479 
487  function addToBodyAttributes( $out, &$bodyAttrs ) {
488  // does nothing by default
489  }
490 
495  function getLogo() {
496  global $wgLogo;
497  return $wgLogo;
498  }
499 
509  public function shouldPreloadLogo() {
510  return false;
511  }
512 
516  function getCategoryLinks() {
517  global $wgUseCategoryBrowser;
518 
519  $out = $this->getOutput();
520  $allCats = $out->getCategoryLinks();
521 
522  if ( !count( $allCats ) ) {
523  return '';
524  }
525 
526  $embed = "<li>";
527  $pop = "</li>";
528 
529  $s = '';
530  $colon = $this->msg( 'colon-separator' )->escaped();
531 
532  if ( !empty( $allCats['normal'] ) ) {
533  $t = $embed . implode( "{$pop}{$embed}", $allCats['normal'] ) . $pop;
534 
535  $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped();
536  $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
537  $title = Title::newFromText( $linkPage );
538  $link = $title ? Linker::link( $title, $msg ) : $msg;
539  $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
540  $link . $colon . '<ul>' . $t . '</ul>' . '</div>';
541  }
542 
543  # Hidden categories
544  if ( isset( $allCats['hidden'] ) ) {
545  if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) {
546  $class = ' mw-hidden-cats-user-shown';
547  } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) {
548  $class = ' mw-hidden-cats-ns-shown';
549  } else {
550  $class = ' mw-hidden-cats-hidden';
551  }
552 
553  $s .= "<div id=\"mw-hidden-catlinks\" class=\"mw-hidden-catlinks$class\">" .
554  $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
555  $colon . '<ul>' . $embed . implode( "{$pop}{$embed}", $allCats['hidden'] ) . $pop . '</ul>' .
556  '</div>';
557  }
558 
559  # optional 'dmoz-like' category browser. Will be shown under the list
560  # of categories an article belong to
561  if ( $wgUseCategoryBrowser ) {
562  $s .= '<br /><hr />';
563 
564  # get a big array of the parents tree
565  $parenttree = $this->getTitle()->getParentCategoryTree();
566  # Skin object passed by reference cause it can not be
567  # accessed under the method subfunction drawCategoryBrowser
568  $tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree ) );
569  # Clean out bogus first entry and sort them
570  unset( $tempout[0] );
571  asort( $tempout );
572  # Output one per line
573  $s .= implode( "<br />\n", $tempout );
574  }
575 
576  return $s;
577  }
578 
584  function drawCategoryBrowser( $tree ) {
585  $return = '';
586 
587  foreach ( $tree as $element => $parent ) {
588  if ( empty( $parent ) ) {
589  # element start a new list
590  $return .= "\n";
591  } else {
592  # grab the others elements
593  $return .= $this->drawCategoryBrowser( $parent ) . ' &gt; ';
594  }
595 
596  # add our current element to the list
597  $eltitle = Title::newFromText( $element );
598  $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) );
599  }
600 
601  return $return;
602  }
603 
607  function getCategories() {
608  $out = $this->getOutput();
609  $catlinks = $this->getCategoryLinks();
610 
611  // Check what we're showing
612  $allCats = $out->getCategoryLinks();
613  $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) ||
614  $this->getTitle()->getNamespace() == NS_CATEGORY;
615 
616  $classes = [ 'catlinks' ];
617  if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
618  $classes[] = 'catlinks-allhidden';
619  }
620 
621  return Html::rawElement(
622  'div',
623  [ 'id' => 'catlinks', 'class' => $classes, 'data-mw' => 'interface' ],
624  $catlinks
625  );
626  }
627 
642  protected function afterContentHook() {
643  $data = '';
644 
645  if ( Hooks::run( 'SkinAfterContent', [ &$data, $this ] ) ) {
646  // adding just some spaces shouldn't toggle the output
647  // of the whole <div/>, so we use trim() here
648  if ( trim( $data ) != '' ) {
649  // Doing this here instead of in the skins to
650  // ensure that the div has the same ID in all
651  // skins
652  $data = "<div id='mw-data-after-content'>\n" .
653  "\t$data\n" .
654  "</div>\n";
655  }
656  } else {
657  wfDebug( "Hook SkinAfterContent changed output processing.\n" );
658  }
659 
660  return $data;
661  }
662 
668  protected function generateDebugHTML() {
669  return MWDebug::getHTMLDebugLog();
670  }
671 
677  function bottomScripts() {
678  // TODO and the suckage continues. This function is really just a wrapper around
679  // OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
680  // up at some point
681  $chunks = [ $this->getOutput()->getBottomScripts() ];
682 
683  // Keep the hook appendage separate to preserve WrappedString objects.
684  // This enables BaseTemplate::getTrail() to merge them where possible.
685  $extraHtml = '';
686  Hooks::run( 'SkinAfterBottomScripts', [ $this, &$extraHtml ] );
687  if ( $extraHtml !== '' ) {
688  $chunks[] = $extraHtml;
689  }
690  return WrappedString::join( "\n", $chunks );
691  }
692 
699  function printSource() {
700  $oldid = $this->getRevisionId();
701  if ( $oldid ) {
702  $canonicalUrl = $this->getTitle()->getCanonicalURL( 'oldid=' . $oldid );
703  $url = htmlspecialchars( wfExpandIRI( $canonicalUrl ) );
704  } else {
705  // oldid not available for non existing pages
706  $url = htmlspecialchars( wfExpandIRI( $this->getTitle()->getCanonicalURL() ) );
707  }
708 
709  return $this->msg( 'retrievedfrom' )
710  ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
711  ->parse();
712  }
713 
717  function getUndeleteLink() {
718  $action = $this->getRequest()->getVal( 'action', 'view' );
719 
720  if ( $this->getTitle()->userCan( 'deletedhistory', $this->getUser() ) &&
721  ( !$this->getTitle()->exists() || $action == 'history' ) ) {
722  $n = $this->getTitle()->isDeleted();
723 
724  if ( $n ) {
725  if ( $this->getTitle()->quickUserCan( 'undelete', $this->getUser() ) ) {
726  $msg = 'thisisdeleted';
727  } else {
728  $msg = 'viewdeleted';
729  }
730 
731  return $this->msg( $msg )->rawParams(
733  SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ),
734  $this->msg( 'restorelink' )->numParams( $n )->escaped() )
735  )->escaped();
736  }
737  }
738 
739  return '';
740  }
741 
746  function subPageSubtitle( $out = null ) {
747  if ( $out === null ) {
748  $out = $this->getOutput();
749  }
750  $title = $out->getTitle();
751  $subpages = '';
752 
753  if ( !Hooks::run( 'SkinSubPageSubtitle', [ &$subpages, $this, $out ] ) ) {
754  return $subpages;
755  }
756 
757  if ( $out->isArticle() && MWNamespace::hasSubpages( $title->getNamespace() ) ) {
758  $ptext = $title->getPrefixedText();
759  if ( strpos( $ptext, '/' ) !== false ) {
760  $links = explode( '/', $ptext );
761  array_pop( $links );
762  $c = 0;
763  $growinglink = '';
764  $display = '';
765  $lang = $this->getLanguage();
766 
767  foreach ( $links as $link ) {
768  $growinglink .= $link;
769  $display .= $link;
770  $linkObj = Title::newFromText( $growinglink );
771 
772  if ( is_object( $linkObj ) && $linkObj->isKnown() ) {
773  $getlink = Linker::linkKnown(
774  $linkObj,
775  htmlspecialchars( $display )
776  );
777 
778  $c++;
779 
780  if ( $c > 1 ) {
781  $subpages .= $lang->getDirMarkEntity() . $this->msg( 'pipe-separator' )->escaped();
782  } else {
783  $subpages .= '&lt; ';
784  }
785 
786  $subpages .= $getlink;
787  $display = '';
788  } else {
789  $display .= '/';
790  }
791  $growinglink .= '/';
792  }
793  }
794  }
795 
796  return $subpages;
797  }
798 
802  function getSearchLink() {
804  return $searchPage->getLocalURL();
805  }
806 
810  function escapeSearchLink() {
811  return htmlspecialchars( $this->getSearchLink() );
812  }
813 
818  function getCopyright( $type = 'detect' ) {
820 
821  if ( $type == 'detect' ) {
822  if ( !$this->isRevisionCurrent()
823  && !$this->msg( 'history_copyright' )->inContentLanguage()->isDisabled()
824  ) {
825  $type = 'history';
826  } else {
827  $type = 'normal';
828  }
829  }
830 
831  if ( $type == 'history' ) {
832  $msg = 'history_copyright';
833  } else {
834  $msg = 'copyright';
835  }
836 
837  if ( $wgRightsPage ) {
838  $title = Title::newFromText( $wgRightsPage );
839  $link = Linker::linkKnown( $title, $wgRightsText );
840  } elseif ( $wgRightsUrl ) {
841  $link = Linker::makeExternalLink( $wgRightsUrl, $wgRightsText );
842  } elseif ( $wgRightsText ) {
844  } else {
845  # Give up now
846  return '';
847  }
848 
849  // Allow for site and per-namespace customization of copyright notice.
850  // @todo Remove deprecated $forContent param from hook handlers and then remove here.
851  $forContent = true;
852 
853  Hooks::run(
854  'SkinCopyrightFooter',
855  [ $this->getTitle(), $type, &$msg, &$link, &$forContent ]
856  );
857 
858  return $this->msg( $msg )->rawParams( $link )->text();
859  }
860 
864  function getCopyrightIcon() {
866 
867  $out = '';
868 
869  if ( $wgFooterIcons['copyright']['copyright'] ) {
870  $out = $wgFooterIcons['copyright']['copyright'];
871  } elseif ( $wgRightsIcon ) {
872  $icon = htmlspecialchars( $wgRightsIcon );
873 
874  if ( $wgRightsUrl ) {
875  $url = htmlspecialchars( $wgRightsUrl );
876  $out .= '<a href="' . $url . '">';
877  }
878 
879  $text = htmlspecialchars( $wgRightsText );
880  $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />";
881 
882  if ( $wgRightsUrl ) {
883  $out .= '</a>';
884  }
885  }
886 
887  return $out;
888  }
889 
894  function getPoweredBy() {
895  global $wgResourceBasePath;
896 
897  $url1 = htmlspecialchars(
898  "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
899  );
900  $url1_5 = htmlspecialchars(
901  "$wgResourceBasePath/resources/assets/poweredby_mediawiki_132x47.png"
902  );
903  $url2 = htmlspecialchars(
904  "$wgResourceBasePath/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  global $wgExternalLinkTarget;
984  $html = Html::rawElement( 'a',
985  [ "href" => $url, "target" => $wgExternalLinkTarget ],
986  $html );
987  }
988  }
989  return $html;
990  }
991 
996  function mainPageLink() {
999  $this->msg( 'mainpage' )->escaped()
1000  );
1001 
1002  return $s;
1003  }
1004 
1011  public function footerLink( $desc, $page ) {
1012  $title = $this->footerLinkTitle( $desc, $page );
1013  if ( !$title ) {
1014  return '';
1015  }
1016 
1017  return Linker::linkKnown(
1018  $title,
1019  $this->msg( $desc )->escaped()
1020  );
1021  }
1022 
1028  private function footerLinkTitle( $desc, $page ) {
1029  // If the link description has been set to "-" in the default language,
1030  if ( $this->msg( $desc )->inContentLanguage()->isDisabled() ) {
1031  // then it is disabled, for all languages.
1032  return null;
1033  }
1034  // Otherwise, we display the link for the user, described in their
1035  // language (which may or may not be the same as the default language),
1036  // but we make the link target be the one site-wide page.
1037  $title = Title::newFromText( $this->msg( $page )->inContentLanguage()->text() );
1038 
1039  return $title ?: null;
1040  }
1041 
1046  function privacyLink() {
1047  return $this->footerLink( 'privacy', 'privacypage' );
1048  }
1049 
1054  function aboutLink() {
1055  return $this->footerLink( 'aboutsite', 'aboutpage' );
1056  }
1057 
1062  function disclaimerLink() {
1063  return $this->footerLink( 'disclaimers', 'disclaimerpage' );
1064  }
1065 
1073  function editUrlOptions() {
1074  $options = [ 'action' => 'edit' ];
1075 
1076  if ( !$this->isRevisionCurrent() ) {
1077  $options['oldid'] = intval( $this->getRevisionId() );
1078  }
1079 
1080  return $options;
1081  }
1082 
1087  function showEmailUser( $id ) {
1088  if ( $id instanceof User ) {
1089  $targetUser = $id;
1090  } else {
1091  $targetUser = User::newFromId( $id );
1092  }
1093 
1094  # The sending user must have a confirmed email address and the receiving
1095  # user must accept emails from the sender.
1096  return $this->getUser()->canSendEmail()
1097  && SpecialEmailUser::validateTarget( $targetUser, $this->getUser() ) === '';
1098  }
1099 
1111  function getSkinStylePath( $name ) {
1112  global $wgStylePath;
1113 
1114  if ( $this->stylename === null ) {
1115  $class = static::class;
1116  throw new MWException( "$class::\$stylename must be set to use getSkinStylePath()" );
1117  }
1118 
1119  return "$wgStylePath/{$this->stylename}/$name";
1120  }
1121 
1122  /* these are used extensively in SkinTemplate, but also some other places */
1123 
1128  static function makeMainPageUrl( $urlaction = '' ) {
1130  self::checkTitle( $title, '' );
1131 
1132  return $title->getLinkURL( $urlaction );
1133  }
1134 
1146  static function makeSpecialUrl( $name, $urlaction = '', $proto = null ) {
1148  if ( is_null( $proto ) ) {
1149  return $title->getLocalURL( $urlaction );
1150  } else {
1151  return $title->getFullURL( $urlaction, false, $proto );
1152  }
1153  }
1154 
1161  static function makeSpecialUrlSubpage( $name, $subpage, $urlaction = '' ) {
1162  $title = SpecialPage::getSafeTitleFor( $name, $subpage );
1163  return $title->getLocalURL( $urlaction );
1164  }
1165 
1171  static function makeI18nUrl( $name, $urlaction = '' ) {
1172  $title = Title::newFromText( wfMessage( $name )->inContentLanguage()->text() );
1173  self::checkTitle( $title, $name );
1174  return $title->getLocalURL( $urlaction );
1175  }
1176 
1182  static function makeUrl( $name, $urlaction = '' ) {
1184  self::checkTitle( $title, $name );
1185 
1186  return $title->getLocalURL( $urlaction );
1187  }
1188 
1195  static function makeInternalOrExternalUrl( $name ) {
1196  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $name ) ) {
1197  return $name;
1198  } else {
1199  return self::makeUrl( $name );
1200  }
1201  }
1202 
1210  static function makeNSUrl( $name, $urlaction = '', $namespace = NS_MAIN ) {
1211  $title = Title::makeTitleSafe( $namespace, $name );
1212  self::checkTitle( $title, $name );
1213 
1214  return $title->getLocalURL( $urlaction );
1215  }
1216 
1223  static function makeUrlDetails( $name, $urlaction = '' ) {
1225  self::checkTitle( $title, $name );
1226 
1227  return [
1228  'href' => $title->getLocalURL( $urlaction ),
1229  'exists' => $title->isKnown(),
1230  ];
1231  }
1232 
1239  static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1241  self::checkTitle( $title, $name );
1242 
1243  return [
1244  'href' => $title->getLocalURL( $urlaction ),
1245  'exists' => true
1246  ];
1247  }
1248 
1255  static function checkTitle( &$title, $name ) {
1256  if ( !is_object( $title ) ) {
1258  if ( !is_object( $title ) ) {
1259  $title = Title::newFromText( '--error: link target missing--' );
1260  }
1261  }
1262  }
1263 
1285  public function buildSidebar() {
1287 
1288  $callback = function ( $old = null, &$ttl = null ) {
1289  $bar = [];
1290  $this->addToSidebar( $bar, 'sidebar' );
1291  Hooks::run( 'SkinBuildSidebar', [ $this, &$bar ] );
1292  if ( MessageCache::singleton()->isDisabled() ) {
1293  $ttl = WANObjectCache::TTL_UNCACHEABLE; // bug T133069
1294  }
1295 
1296  return $bar;
1297  };
1298 
1299  $msgCache = MessageCache::singleton();
1300  $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1301 
1302  $sidebar = $wgEnableSidebarCache
1303  ? $wanCache->getWithSetCallback(
1304  $wanCache->makeKey( 'sidebar', $this->getLanguage()->getCode() ),
1305  $wgSidebarCacheExpiry,
1306  $callback,
1307  [
1308  'checkKeys' => [
1309  // Unless there is both no exact $code override nor an i18n definition
1310  // in the software, the only MediaWiki page to check is for $code.
1311  $msgCache->getCheckKey( $this->getLanguage()->getCode() )
1312  ],
1313  'lockTSE' => 30
1314  ]
1315  )
1316  : $callback();
1317 
1318  // Apply post-processing to the cached value
1319  Hooks::run( 'SidebarBeforeOutput', [ $this, &$sidebar ] );
1320 
1321  return $sidebar;
1322  }
1323 
1333  public function addToSidebar( &$bar, $message ) {
1334  $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1335  }
1336 
1344  function addToSidebarPlain( &$bar, $text ) {
1345  $lines = explode( "\n", $text );
1346 
1347  $heading = '';
1348  $messageTitle = $this->getConfig()->get( 'EnableSidebarCache' )
1349  ? Title::newMainPage() : $this->getTitle();
1350 
1351  foreach ( $lines as $line ) {
1352  if ( strpos( $line, '*' ) !== 0 ) {
1353  continue;
1354  }
1355  $line = rtrim( $line, "\r" ); // for Windows compat
1356 
1357  if ( strpos( $line, '**' ) !== 0 ) {
1358  $heading = trim( $line, '* ' );
1359  if ( !array_key_exists( $heading, $bar ) ) {
1360  $bar[$heading] = [];
1361  }
1362  } else {
1363  $line = trim( $line, '* ' );
1364 
1365  if ( strpos( $line, '|' ) !== false ) { // sanity check
1366  $line = MessageCache::singleton()->transform( $line, false, null, $messageTitle );
1367  $line = array_map( 'trim', explode( '|', $line, 2 ) );
1368  if ( count( $line ) !== 2 ) {
1369  // Second sanity check, could be hit by people doing
1370  // funky stuff with parserfuncs... (T35321)
1371  continue;
1372  }
1373 
1374  $extraAttribs = [];
1375 
1376  $msgLink = $this->msg( $line[0] )->title( $messageTitle )->inContentLanguage();
1377  if ( $msgLink->exists() ) {
1378  $link = $msgLink->text();
1379  if ( $link == '-' ) {
1380  continue;
1381  }
1382  } else {
1383  $link = $line[0];
1384  }
1385  $msgText = $this->msg( $line[1] )->title( $messageTitle );
1386  if ( $msgText->exists() ) {
1387  $text = $msgText->text();
1388  } else {
1389  $text = $line[1];
1390  }
1391 
1392  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $link ) ) {
1393  $href = $link;
1394 
1395  // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1397  if ( $wgNoFollowLinks && !wfMatchesDomainList( $href, $wgNoFollowDomainExceptions ) ) {
1398  $extraAttribs['rel'] = 'nofollow';
1399  }
1400 
1401  global $wgExternalLinkTarget;
1402  if ( $wgExternalLinkTarget ) {
1403  $extraAttribs['target'] = $wgExternalLinkTarget;
1404  }
1405  } else {
1407 
1408  if ( $title ) {
1409  $title = $title->fixSpecialName();
1410  $href = $title->getLinkURL();
1411  } else {
1412  $href = 'INVALID-TITLE';
1413  }
1414  }
1415 
1416  $bar[$heading][] = array_merge( [
1417  'text' => $text,
1418  'href' => $href,
1419  'id' => Sanitizer::escapeIdForAttribute( 'n-' . strtr( $line[1], ' ', '-' ) ),
1420  'active' => false,
1421  ], $extraAttribs );
1422  } else {
1423  continue;
1424  }
1425  }
1426  }
1427 
1428  return $bar;
1429  }
1430 
1436  function getNewtalks() {
1437  $newMessagesAlert = '';
1438  $user = $this->getUser();
1439  $newtalks = $user->getNewMessageLinks();
1440  $out = $this->getOutput();
1441 
1442  // Allow extensions to disable or modify the new messages alert
1443  if ( !Hooks::run( 'GetNewMessagesAlert', [ &$newMessagesAlert, $newtalks, $user, $out ] ) ) {
1444  return '';
1445  }
1446  if ( $newMessagesAlert ) {
1447  return $newMessagesAlert;
1448  }
1449 
1450  if ( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) {
1451  $uTalkTitle = $user->getTalkPage();
1452  $lastSeenRev = $newtalks[0]['rev'] ?? null;
1453  $nofAuthors = 0;
1454  if ( $lastSeenRev !== null ) {
1455  $plural = true; // Default if we have a last seen revision: if unknown, use plural
1456  $latestRev = Revision::newFromTitle( $uTalkTitle, false, Revision::READ_NORMAL );
1457  if ( $latestRev !== null ) {
1458  // Singular if only 1 unseen revision, plural if several unseen revisions.
1459  $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1460  $nofAuthors = $uTalkTitle->countAuthorsBetween(
1461  $lastSeenRev, $latestRev, 10, 'include_new' );
1462  }
1463  } else {
1464  // Singular if no revision -> diff link will show latest change only in any case
1465  $plural = false;
1466  }
1467  $plural = $plural ? 999 : 1;
1468  // 999 signifies "more than one revision". We don't know how many, and even if we did,
1469  // the number of revisions or authors is not necessarily the same as the number of
1470  // "messages".
1471  $newMessagesLink = Linker::linkKnown(
1472  $uTalkTitle,
1473  $this->msg( 'newmessageslinkplural' )->params( $plural )->escaped(),
1474  [],
1475  $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1476  );
1477 
1478  $newMessagesDiffLink = Linker::linkKnown(
1479  $uTalkTitle,
1480  $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->escaped(),
1481  [],
1482  $lastSeenRev !== null
1483  ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1484  : [ 'diff' => 'cur' ]
1485  );
1486 
1487  if ( $nofAuthors >= 1 && $nofAuthors <= 10 ) {
1488  $newMessagesAlert = $this->msg(
1489  'youhavenewmessagesfromusers',
1490  $newMessagesLink,
1491  $newMessagesDiffLink
1492  )->numParams( $nofAuthors, $plural );
1493  } else {
1494  // $nofAuthors === 11 signifies "11 or more" ("more than 10")
1495  $newMessagesAlert = $this->msg(
1496  $nofAuthors > 10 ? 'youhavenewmessagesmanyusers' : 'youhavenewmessages',
1497  $newMessagesLink,
1498  $newMessagesDiffLink
1499  )->numParams( $plural );
1500  }
1501  $newMessagesAlert = $newMessagesAlert->text();
1502  # Disable CDN cache
1503  $out->setCdnMaxage( 0 );
1504  } elseif ( count( $newtalks ) ) {
1505  $sep = $this->msg( 'newtalkseparator' )->escaped();
1506  $msgs = [];
1507 
1508  foreach ( $newtalks as $newtalk ) {
1509  $msgs[] = Xml::element(
1510  'a',
1511  [ 'href' => $newtalk['link'] ], $newtalk['wiki']
1512  );
1513  }
1514  $parts = implode( $sep, $msgs );
1515  $newMessagesAlert = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped();
1516  $out->setCdnMaxage( 0 );
1517  }
1518 
1519  return $newMessagesAlert;
1520  }
1521 
1529  private function getCachedNotice( $name ) {
1530  global $wgRenderHashAppend;
1531 
1532  $needParse = false;
1533 
1534  if ( $name === 'default' ) {
1535  // special case
1536  global $wgSiteNotice;
1537  $notice = $wgSiteNotice;
1538  if ( empty( $notice ) ) {
1539  return false;
1540  }
1541  } else {
1542  $msg = $this->msg( $name )->inContentLanguage();
1543  if ( $msg->isBlank() ) {
1544  return '';
1545  } elseif ( $msg->isDisabled() ) {
1546  return false;
1547  }
1548  $notice = $msg->plain();
1549  }
1550 
1551  $services = MediaWikiServices::getInstance();
1552  $cache = $services->getMainWANObjectCache();
1553  $parsed = $cache->getWithSetCallback(
1554  // Use the extra hash appender to let eg SSL variants separately cache
1555  // Key is verified with md5 hash of unparsed wikitext
1556  $cache->makeKey( $name, $wgRenderHashAppend, md5( $notice ) ),
1557  // TTL in seconds
1558  600,
1559  function () use ( $notice ) {
1560  return $this->getOutput()->parse( $notice );
1561  }
1562  );
1563 
1564  $contLang = $services->getContentLanguage();
1565  return Html::rawElement(
1566  'div',
1567  [
1568  'id' => 'localNotice',
1569  'lang' => $contLang->getHtmlCode(),
1570  'dir' => $contLang->getDir()
1571  ],
1572  $parsed
1573  );
1574  }
1575 
1581  function getSiteNotice() {
1582  $siteNotice = '';
1583 
1584  if ( Hooks::run( 'SiteNoticeBefore', [ &$siteNotice, $this ] ) ) {
1585  if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
1586  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1587  } else {
1588  $anonNotice = $this->getCachedNotice( 'anonnotice' );
1589  if ( $anonNotice === false ) {
1590  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1591  } else {
1592  $siteNotice = $anonNotice;
1593  }
1594  }
1595  if ( $siteNotice === false ) {
1596  $siteNotice = $this->getCachedNotice( 'default' );
1597  }
1598  }
1599 
1600  Hooks::run( 'SiteNoticeAfter', [ &$siteNotice, $this ] );
1601  return $siteNotice;
1602  }
1603 
1617  public function doEditSectionLink( Title $nt, $section, $tooltip, Language $lang ) {
1618  // HTML generated here should probably have userlangattributes
1619  // added to it for LTR text on RTL pages
1620 
1621  $attribs = [];
1622  if ( !is_null( $tooltip ) ) {
1623  $attribs['title'] = $this->msg( 'editsectionhint' )->rawParams( $tooltip )
1624  ->inLanguage( $lang )->text();
1625  }
1626 
1627  $links = [
1628  'editsection' => [
1629  'text' => $this->msg( 'editsection' )->inLanguage( $lang )->escaped(),
1630  'targetTitle' => $nt,
1631  'attribs' => $attribs,
1632  'query' => [ 'action' => 'edit', 'section' => $section ],
1633  'options' => [ 'noclasses', 'known' ]
1634  ]
1635  ];
1636 
1637  Hooks::run( 'SkinEditSectionLinks', [ $this, $nt, $section, $tooltip, &$links, $lang ] );
1638 
1639  $result = '<span class="mw-editsection"><span class="mw-editsection-bracket">[</span>';
1640 
1641  $linksHtml = [];
1642  foreach ( $links as $k => $linkDetails ) {
1643  $linksHtml[] = Linker::link(
1644  $linkDetails['targetTitle'],
1645  $linkDetails['text'],
1646  $linkDetails['attribs'],
1647  $linkDetails['query'],
1648  $linkDetails['options']
1649  );
1650  }
1651 
1652  $result .= implode(
1653  '<span class="mw-editsection-divider">'
1654  . $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
1655  . '</span>',
1656  $linksHtml
1657  );
1658 
1659  $result .= '<span class="mw-editsection-bracket">]</span></span>';
1660  return $result;
1661  }
1662 
1663 }
showEmailUser( $id)
Definition: Skin.php:1087
static makeUrlDetails( $name, $urlaction='')
these return an array with the &#39;href&#39; and boolean &#39;exists&#39;
Definition: Skin.php:1223
static makeI18nUrl( $name, $urlaction='')
Definition: Skin.php:1171
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.
$wgFooterIcons
Abstract list of footer icons for skins in place of old copyrightico and poweredbyico code You can ad...
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:2046
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
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub 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:822
footerLinkTitle( $desc, $page)
Definition: Skin.php:1028
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:2107
static getTimestampFromId( $title, $id, $flags=0)
Get rev_timestamp from rev_id, without loading the rest of the row.
Definition: Revision.php:1280
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e...
Definition: Skin.php:642
$wgRightsUrl
Set this to specify an external URL containing details about the content license used on your wiki...
setRelevantUser( $u)
Set the "relevant" user.
Definition: Skin.php:356
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:894
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1436
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:1146
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:597
static isIP( $name)
Does the string match an anonymous IP address?
Definition: User.php:971
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:1285
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:1046
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:1617
initPage(OutputPage $out)
Definition: Skin.php:162
editUrlOptions()
Return URL options for the &#39;edit page&#39; link.
Definition: Skin.php:1073
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
getLogo()
URL to the logo.
Definition: Skin.php:495
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:57
getCopyrightIcon()
Definition: Skin.php:864
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:1529
$wgSidebarCacheExpiry
Expiry time for the sidebar cache, in seconds.
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:138
shouldPreloadLogo()
Whether the logo should be preloaded with an HTTP link header or not.
Definition: Skin.php:509
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:607
getSiteNotice()
Get the site notice.
Definition: Skin.php:1581
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area. ...
Definition: MWDebug.php:456
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. 'LanguageGetMagic':DEPRECATED since 1.16! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) '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 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) '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:2044
getPageClasses( $title)
TODO: document.
Definition: Skin.php:442
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:3100
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:487
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:47
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:2046
$wgRenderHashAppend
Append a configured value to the parser cache and the sitenotice key so that they can be kept separat...
preloadExistence()
Preload the existence of three commonly-requested pages in a single query.
Definition: Skin.php:266
footerLink( $desc, $page)
Returns an HTML link for use in the footer.
Definition: Skin.php:1011
$wgStylePath
The URL path of the skins directory.
$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
$wgNoFollowLinks
If true, external URL links in wiki text will be given the rel="nofollow" attribute as a hint to sear...
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:2280
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1255
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:1728
mainPageLink()
Gets the link to the wiki&#39;s main page.
Definition: Skin.php:996
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:1270
drawCategoryBrowser( $tree)
Render the array as a series of links.
Definition: Skin.php:584
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:344
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:746
getCategoryLinks()
Definition: Skin.php:516
disclaimerLink()
Gets the link to the wiki&#39;s general disclaimers page.
Definition: Skin.php:1062
$wgUseCategoryBrowser
Use experimental, DMOZ-like category browser.
$cache
Definition: mcc.php:33
getSearchLink()
Definition: Skin.php:802
$mRelevantUser
Definition: Skin.php:45
const NS_CATEGORY
Definition: Defines.php:78
static makeVariablesScript( $data, $nonce=null)
Definition: Skin.php:404
$wgResourceBasePath
The default &#39;remoteBasePath&#39; value for instances of ResourceLoaderFileModule.
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:2046
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:826
$wgNoFollowDomainExceptions
If this is set to an array of domains, external links to these domain names (or any subdomains) will ...
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:2046
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:668
setRelevantTitle( $t)
Set the "relevant" title.
Definition: Skin.php:330
getHtmlElementAttributes()
Return values for <html> element.
Definition: Skin.php:471
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:973
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1399
$wgRightsPage
Override for copyright metadata.
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:368
$wgRightsText
If either $wgRightsUrl or $wgRightsPage is specified then this variable gives the text for the link...
aboutLink()
Gets the link to the wiki&#39;s about page.
Definition: Skin.php:1054
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition: Skin.php:1344
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition: Skin.php:1333
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:1239
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:3100
static makeUrl( $name, $urlaction='')
Definition: Skin.php:1182
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:573
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page...
Definition: Skin.php:699
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:615
string $stylename
Stylesheets set to use.
Definition: Skin.php:51
$fallback
Definition: MessagesAb.php:11
$lines
Definition: router.php:61
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:320
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:141
$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:1210
$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:818
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
$wgLogo
The URL path of the wiki logo.
$wgFallbackSkin
Fallback skin used when the skin defined by $wgDefaultSkin can&#39;t be found.
$wgSiteNotice
Site notice shown at the top of each page.
getUndeleteLink()
Definition: Skin.php:717
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
$messages
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1195
getSkinStylePath( $name)
Return a fully resolved style path URL to images or styles stored in the current skin&#39;s folder...
Definition: Skin.php:1111
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:420
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:592
setupSkinUserCss(OutputPage $out)
Hook point for adding style modules to OutputPage.
Definition: Skin.php:433
static makeMainPageUrl( $urlaction='')
Definition: Skin.php:1128
$searchPage
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:84
$wgExternalLinkTarget
Set a default target for external links, e.g.
$wgRightsIcon
Override for copyright metadata.
getRevisionId()
Get the current revision ID.
Definition: Skin.php:311
escapeSearchLink()
Definition: Skin.php:810
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:677
static singleton()
Get the signleton instance of this class.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition: hooks.txt:244
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1161
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
$wgEnableSidebarCache
If on, the sidebar navigation links are cached for users with the current language set...
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:280