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  ],
200  // modules that enhance the content in some way
201  'content' => [
202  'mediawiki.page.ready',
203  ],
204  // modules relating to search functionality
205  'search' => [
206  'mediawiki.searchSuggest',
207  ],
208  // modules relating to functionality relating to watching an article
209  'watch' => [],
210  // modules which relate to the current users preferences
211  'user' => [],
212  // modules relating to RSS/Atom Feeds
213  'syndicate' => [],
214  ];
215 
216  // Preload jquery.tablesorter for mediawiki.page.ready
217  if ( strpos( $out->getHTML(), 'sortable' ) !== false ) {
218  $modules['content'][] = 'jquery.tablesorter';
219  }
220 
221  // Preload jquery.makeCollapsible for mediawiki.page.ready
222  if ( strpos( $out->getHTML(), 'mw-collapsible' ) !== false ) {
223  $modules['content'][] = 'jquery.makeCollapsible';
224  $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
225  }
226 
227  // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
228  // on every page is deprecated. Express a dependency instead.
229  if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
230  $modules['styles']['content'][] = 'mediawiki.ui.button';
231  }
232 
233  if ( $out->isTOCEnabled() ) {
234  $modules['content'][] = 'mediawiki.toc';
235  $modules['styles']['content'][] = 'mediawiki.toc.styles';
236  }
237 
238  // Add various resources if required
239  if ( $user->isLoggedIn()
240  && $user->isAllowedAll( 'writeapi', 'viewmywatchlist', 'editmywatchlist' )
241  && $this->getRelevantTitle()->canExist()
242  ) {
243  $modules['watch'][] = 'mediawiki.page.watch.ajax';
244  }
245 
246  if ( $user->getBoolOption( 'editsectiononrightclick' ) ) {
247  $modules['user'][] = 'mediawiki.action.view.rightClickEdit';
248  }
249 
250  // Crazy edit-on-double-click stuff
251  if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) {
252  $modules['user'][] = 'mediawiki.action.view.dblClickEdit';
253  }
254 
255  if ( $out->isSyndicated() ) {
256  $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
257  }
258 
259  return $modules;
260  }
261 
265  protected function preloadExistence() {
266  $titles = [];
267 
268  // User/talk link
269  $user = $this->getUser();
270  if ( $user->isLoggedIn() ) {
271  $titles[] = $user->getUserPage();
272  $titles[] = $user->getTalkPage();
273  }
274 
275  // Check, if the page can hold some kind of content, otherwise do nothing
276  $title = $this->getRelevantTitle();
277  if ( $title->canExist() ) {
278  if ( $title->isTalkPage() ) {
279  $titles[] = $title->getSubjectPage();
280  } else {
281  $titles[] = $title->getTalkPage();
282  }
283  }
284 
285  // Footer links (used by SkinTemplate::prepareQuickTemplate)
286  foreach ( [
287  $this->footerLinkTitle( 'privacy', 'privacypage' ),
288  $this->footerLinkTitle( 'aboutsite', 'aboutpage' ),
289  $this->footerLinkTitle( 'disclaimers', 'disclaimerpage' ),
290  ] as $title ) {
291  if ( $title ) {
292  $titles[] = $title;
293  }
294  }
295 
296  Hooks::run( 'SkinPreloadExistence', [ &$titles, $this ] );
297 
298  if ( $titles ) {
299  $lb = new LinkBatch( $titles );
300  $lb->setCaller( __METHOD__ );
301  $lb->execute();
302  }
303  }
304 
310  public function getRevisionId() {
311  return $this->getOutput()->getRevisionId();
312  }
313 
319  public function isRevisionCurrent() {
320  $revID = $this->getRevisionId();
321  return $revID == 0 || $revID == $this->getTitle()->getLatestRevID();
322  }
323 
329  public function setRelevantTitle( $t ) {
330  $this->mRelevantTitle = $t;
331  }
332 
343  public function getRelevantTitle() {
344  return $this->mRelevantTitle ?? $this->getTitle();
345  }
346 
352  public function setRelevantUser( $u ) {
353  $this->mRelevantUser = $u;
354  }
355 
364  public function getRelevantUser() {
365  if ( isset( $this->mRelevantUser ) ) {
366  return $this->mRelevantUser;
367  }
368  $title = $this->getRelevantTitle();
369  if ( $title->hasSubjectNamespace( NS_USER ) ) {
370  $rootUser = $title->getRootText();
371  if ( User::isIP( $rootUser ) ) {
372  $this->mRelevantUser = User::newFromName( $rootUser, false );
373  } else {
374  $user = User::newFromName( $rootUser, false );
375 
376  if ( $user ) {
377  $user->load( User::READ_NORMAL );
378 
379  if ( $user->isLoggedIn() ) {
380  $this->mRelevantUser = $user;
381  }
382  }
383  }
384  return $this->mRelevantUser;
385  }
386  return null;
387  }
388 
393  abstract function outputPage( OutputPage $out = null );
394 
400  public static function makeVariablesScript( $data, $nonce = null ) {
401  if ( $data ) {
404  $nonce
405  );
406  }
407  return '';
408  }
409 
416  public static function getDynamicStylesheetQuery() {
417  return [
418  'action' => 'raw',
419  'ctype' => 'text/css',
420  ];
421  }
422 
429  public function setupSkinUserCss( OutputPage $out ) {
430  // Stub.
431  }
432 
438  function getPageClasses( $title ) {
439  $numeric = 'ns-' . $title->getNamespace();
440  $user = $this->getUser();
441 
442  if ( $title->isSpecialPage() ) {
443  $type = 'ns-special';
444  // T25315: provide a class based on the canonical special page name without subpages
445  list( $canonicalName ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
446  resolveAlias( $title->getDBkey() );
447  if ( $canonicalName ) {
448  $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
449  } else {
450  $type .= ' mw-invalidspecialpage';
451  }
452  } else {
453  if ( $title->isTalkPage() ) {
454  $type = 'ns-talk';
455  } else {
456  $type = 'ns-subject';
457  }
458  // T208315: add HTML class when the user can edit the page
459  if ( $title->quickUserCan( 'edit', $user ) ) {
460  $type .= ' mw-editable';
461  }
462  }
463 
464  $name = Sanitizer::escapeClass( 'page-' . $title->getPrefixedText() );
465  $root = Sanitizer::escapeClass( 'rootpage-' . $title->getRootTitle()->getPrefixedText() );
466 
467  return "$numeric $type $name $root";
468  }
469 
474  public function getHtmlElementAttributes() {
475  $lang = $this->getLanguage();
476  return [
477  'lang' => $lang->getHtmlCode(),
478  'dir' => $lang->getDir(),
479  'class' => 'client-nojs',
480  ];
481  }
482 
490  function addToBodyAttributes( $out, &$bodyAttrs ) {
491  // does nothing by default
492  }
493 
498  function getLogo() {
499  global $wgLogo;
500  return $wgLogo;
501  }
502 
512  public function shouldPreloadLogo() {
513  return false;
514  }
515 
519  function getCategoryLinks() {
520  global $wgUseCategoryBrowser;
521 
522  $out = $this->getOutput();
523  $allCats = $out->getCategoryLinks();
524 
525  if ( !count( $allCats ) ) {
526  return '';
527  }
528 
529  $embed = "<li>";
530  $pop = "</li>";
531 
532  $s = '';
533  $colon = $this->msg( 'colon-separator' )->escaped();
534 
535  if ( !empty( $allCats['normal'] ) ) {
536  $t = $embed . implode( "{$pop}{$embed}", $allCats['normal'] ) . $pop;
537 
538  $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped();
539  $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
540  $title = Title::newFromText( $linkPage );
541  $link = $title ? Linker::link( $title, $msg ) : $msg;
542  $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
543  $link . $colon . '<ul>' . $t . '</ul>' . '</div>';
544  }
545 
546  # Hidden categories
547  if ( isset( $allCats['hidden'] ) ) {
548  if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) {
549  $class = ' mw-hidden-cats-user-shown';
550  } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) {
551  $class = ' mw-hidden-cats-ns-shown';
552  } else {
553  $class = ' mw-hidden-cats-hidden';
554  }
555 
556  $s .= "<div id=\"mw-hidden-catlinks\" class=\"mw-hidden-catlinks$class\">" .
557  $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
558  $colon . '<ul>' . $embed . implode( "{$pop}{$embed}", $allCats['hidden'] ) . $pop . '</ul>' .
559  '</div>';
560  }
561 
562  # optional 'dmoz-like' category browser. Will be shown under the list
563  # of categories an article belong to
564  if ( $wgUseCategoryBrowser ) {
565  $s .= '<br /><hr />';
566 
567  # get a big array of the parents tree
568  $parenttree = $this->getTitle()->getParentCategoryTree();
569  # Skin object passed by reference cause it can not be
570  # accessed under the method subfunction drawCategoryBrowser
571  $tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree ) );
572  # Clean out bogus first entry and sort them
573  unset( $tempout[0] );
574  asort( $tempout );
575  # Output one per line
576  $s .= implode( "<br />\n", $tempout );
577  }
578 
579  return $s;
580  }
581 
587  function drawCategoryBrowser( $tree ) {
588  $return = '';
589 
590  foreach ( $tree as $element => $parent ) {
591  if ( empty( $parent ) ) {
592  # element start a new list
593  $return .= "\n";
594  } else {
595  # grab the others elements
596  $return .= $this->drawCategoryBrowser( $parent ) . ' &gt; ';
597  }
598 
599  # add our current element to the list
600  $eltitle = Title::newFromText( $element );
601  $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) );
602  }
603 
604  return $return;
605  }
606 
610  function getCategories() {
611  $out = $this->getOutput();
612  $catlinks = $this->getCategoryLinks();
613 
614  // Check what we're showing
615  $allCats = $out->getCategoryLinks();
616  $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) ||
617  $this->getTitle()->getNamespace() == NS_CATEGORY;
618 
619  $classes = [ 'catlinks' ];
620  if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
621  $classes[] = 'catlinks-allhidden';
622  }
623 
624  return Html::rawElement(
625  'div',
626  [ 'id' => 'catlinks', 'class' => $classes, 'data-mw' => 'interface' ],
627  $catlinks
628  );
629  }
630 
645  protected function afterContentHook() {
646  $data = '';
647 
648  if ( Hooks::run( 'SkinAfterContent', [ &$data, $this ] ) ) {
649  // adding just some spaces shouldn't toggle the output
650  // of the whole <div/>, so we use trim() here
651  if ( trim( $data ) != '' ) {
652  // Doing this here instead of in the skins to
653  // ensure that the div has the same ID in all
654  // skins
655  $data = "<div id='mw-data-after-content'>\n" .
656  "\t$data\n" .
657  "</div>\n";
658  }
659  } else {
660  wfDebug( "Hook SkinAfterContent changed output processing.\n" );
661  }
662 
663  return $data;
664  }
665 
671  protected function generateDebugHTML() {
672  return MWDebug::getHTMLDebugLog();
673  }
674 
680  function bottomScripts() {
681  // TODO and the suckage continues. This function is really just a wrapper around
682  // OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
683  // up at some point
684  $chunks = [ $this->getOutput()->getBottomScripts() ];
685 
686  // Keep the hook appendage separate to preserve WrappedString objects.
687  // This enables BaseTemplate::getTrail() to merge them where possible.
688  $extraHtml = '';
689  Hooks::run( 'SkinAfterBottomScripts', [ $this, &$extraHtml ] );
690  if ( $extraHtml !== '' ) {
691  $chunks[] = $extraHtml;
692  }
693  return WrappedString::join( "\n", $chunks );
694  }
695 
702  function printSource() {
703  $oldid = $this->getRevisionId();
704  if ( $oldid ) {
705  $canonicalUrl = $this->getTitle()->getCanonicalURL( 'oldid=' . $oldid );
706  $url = htmlspecialchars( wfExpandIRI( $canonicalUrl ) );
707  } else {
708  // oldid not available for non existing pages
709  $url = htmlspecialchars( wfExpandIRI( $this->getTitle()->getCanonicalURL() ) );
710  }
711 
712  return $this->msg( 'retrievedfrom' )
713  ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
714  ->parse();
715  }
716 
720  function getUndeleteLink() {
721  $action = $this->getRequest()->getVal( 'action', 'view' );
722 
723  if ( $this->getTitle()->userCan( 'deletedhistory', $this->getUser() ) &&
724  ( !$this->getTitle()->exists() || $action == 'history' ) ) {
725  $n = $this->getTitle()->isDeleted();
726 
727  if ( $n ) {
728  if ( $this->getTitle()->quickUserCan( 'undelete', $this->getUser() ) ) {
729  $msg = 'thisisdeleted';
730  } else {
731  $msg = 'viewdeleted';
732  }
733 
734  return $this->msg( $msg )->rawParams(
736  SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ),
737  $this->msg( 'restorelink' )->numParams( $n )->escaped() )
738  )->escaped();
739  }
740  }
741 
742  return '';
743  }
744 
749  function subPageSubtitle( $out = null ) {
750  if ( $out === null ) {
751  $out = $this->getOutput();
752  }
753  $title = $out->getTitle();
754  $subpages = '';
755 
756  if ( !Hooks::run( 'SkinSubPageSubtitle', [ &$subpages, $this, $out ] ) ) {
757  return $subpages;
758  }
759 
760  if ( $out->isArticle() && MWNamespace::hasSubpages( $title->getNamespace() ) ) {
761  $ptext = $title->getPrefixedText();
762  if ( strpos( $ptext, '/' ) !== false ) {
763  $links = explode( '/', $ptext );
764  array_pop( $links );
765  $c = 0;
766  $growinglink = '';
767  $display = '';
768  $lang = $this->getLanguage();
769 
770  foreach ( $links as $link ) {
771  $growinglink .= $link;
772  $display .= $link;
773  $linkObj = Title::newFromText( $growinglink );
774 
775  if ( is_object( $linkObj ) && $linkObj->isKnown() ) {
776  $getlink = Linker::linkKnown(
777  $linkObj,
778  htmlspecialchars( $display )
779  );
780 
781  $c++;
782 
783  if ( $c > 1 ) {
784  $subpages .= $lang->getDirMarkEntity() . $this->msg( 'pipe-separator' )->escaped();
785  } else {
786  $subpages .= '&lt; ';
787  }
788 
789  $subpages .= $getlink;
790  $display = '';
791  } else {
792  $display .= '/';
793  }
794  $growinglink .= '/';
795  }
796  }
797  }
798 
799  return $subpages;
800  }
801 
805  function getSearchLink() {
807  return $searchPage->getLocalURL();
808  }
809 
813  function escapeSearchLink() {
814  return htmlspecialchars( $this->getSearchLink() );
815  }
816 
821  function getCopyright( $type = 'detect' ) {
823 
824  if ( $type == 'detect' ) {
825  if ( !$this->isRevisionCurrent()
826  && !$this->msg( 'history_copyright' )->inContentLanguage()->isDisabled()
827  ) {
828  $type = 'history';
829  } else {
830  $type = 'normal';
831  }
832  }
833 
834  if ( $type == 'history' ) {
835  $msg = 'history_copyright';
836  } else {
837  $msg = 'copyright';
838  }
839 
840  if ( $wgRightsPage ) {
841  $title = Title::newFromText( $wgRightsPage );
842  $link = Linker::linkKnown( $title, $wgRightsText );
843  } elseif ( $wgRightsUrl ) {
844  $link = Linker::makeExternalLink( $wgRightsUrl, $wgRightsText );
845  } elseif ( $wgRightsText ) {
847  } else {
848  # Give up now
849  return '';
850  }
851 
852  // Allow for site and per-namespace customization of copyright notice.
853  // @todo Remove deprecated $forContent param from hook handlers and then remove here.
854  $forContent = true;
855 
856  Hooks::run(
857  'SkinCopyrightFooter',
858  [ $this->getTitle(), $type, &$msg, &$link, &$forContent ]
859  );
860 
861  return $this->msg( $msg )->rawParams( $link )->text();
862  }
863 
867  function getCopyrightIcon() {
869 
870  $out = '';
871 
872  if ( $wgFooterIcons['copyright']['copyright'] ) {
873  $out = $wgFooterIcons['copyright']['copyright'];
874  } elseif ( $wgRightsIcon ) {
875  $icon = htmlspecialchars( $wgRightsIcon );
876 
877  if ( $wgRightsUrl ) {
878  $url = htmlspecialchars( $wgRightsUrl );
879  $out .= '<a href="' . $url . '">';
880  }
881 
882  $text = htmlspecialchars( $wgRightsText );
883  $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />";
884 
885  if ( $wgRightsUrl ) {
886  $out .= '</a>';
887  }
888  }
889 
890  return $out;
891  }
892 
897  function getPoweredBy() {
898  global $wgResourceBasePath;
899 
900  $url1 = htmlspecialchars(
901  "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
902  );
903  $url1_5 = htmlspecialchars(
904  "$wgResourceBasePath/resources/assets/poweredby_mediawiki_132x47.png"
905  );
906  $url2 = htmlspecialchars(
907  "$wgResourceBasePath/resources/assets/poweredby_mediawiki_176x62.png"
908  );
909  $text = '<a href="//www.mediawiki.org/"><img src="' . $url1
910  . '" srcset="' . $url1_5 . ' 1.5x, ' . $url2 . ' 2x" '
911  . 'height="31" width="88" alt="Powered by MediaWiki" /></a>';
912  Hooks::run( 'SkinGetPoweredBy', [ &$text, $this ] );
913  return $text;
914  }
915 
921  protected function lastModified() {
922  $timestamp = $this->getOutput()->getRevisionTimestamp();
923 
924  # No cached timestamp, load it from the database
925  if ( $timestamp === null ) {
926  $timestamp = Revision::getTimestampFromId( $this->getTitle(), $this->getRevisionId() );
927  }
928 
929  if ( $timestamp ) {
930  $d = $this->getLanguage()->userDate( $timestamp, $this->getUser() );
931  $t = $this->getLanguage()->userTime( $timestamp, $this->getUser() );
932  $s = ' ' . $this->msg( 'lastmodifiedat', $d, $t )->parse();
933  } else {
934  $s = '';
935  }
936 
937  if ( MediaWikiServices::getInstance()->getDBLoadBalancer()->getLaggedReplicaMode() ) {
938  $s .= ' <strong>' . $this->msg( 'laggedslavemode' )->parse() . '</strong>';
939  }
940 
941  return $s;
942  }
943 
948  function logoText( $align = '' ) {
949  if ( $align != '' ) {
950  $a = " style='float: {$align};'";
951  } else {
952  $a = '';
953  }
954 
955  $mp = $this->msg( 'mainpage' )->escaped();
956  $mptitle = Title::newMainPage();
957  $url = ( is_object( $mptitle ) ? htmlspecialchars( $mptitle->getLocalURL() ) : '' );
958 
959  $logourl = $this->getLogo();
960  $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
961 
962  return $s;
963  }
964 
973  function makeFooterIcon( $icon, $withImage = 'withImage' ) {
974  if ( is_string( $icon ) ) {
975  $html = $icon;
976  } else { // Assuming array
977  $url = $icon["url"] ?? null;
978  unset( $icon["url"] );
979  if ( isset( $icon["src"] ) && $withImage === 'withImage' ) {
980  // do this the lazy way, just pass icon data as an attribute array
981  $html = Html::element( 'img', $icon );
982  } else {
983  $html = htmlspecialchars( $icon["alt"] );
984  }
985  if ( $url ) {
986  global $wgExternalLinkTarget;
987  $html = Html::rawElement( 'a',
988  [ "href" => $url, "target" => $wgExternalLinkTarget ],
989  $html );
990  }
991  }
992  return $html;
993  }
994 
999  function mainPageLink() {
1002  $this->msg( 'mainpage' )->escaped()
1003  );
1004 
1005  return $s;
1006  }
1007 
1014  public function footerLink( $desc, $page ) {
1015  $title = $this->footerLinkTitle( $desc, $page );
1016  if ( !$title ) {
1017  return '';
1018  }
1019 
1020  return Linker::linkKnown(
1021  $title,
1022  $this->msg( $desc )->escaped()
1023  );
1024  }
1025 
1031  private function footerLinkTitle( $desc, $page ) {
1032  // If the link description has been set to "-" in the default language,
1033  if ( $this->msg( $desc )->inContentLanguage()->isDisabled() ) {
1034  // then it is disabled, for all languages.
1035  return null;
1036  }
1037  // Otherwise, we display the link for the user, described in their
1038  // language (which may or may not be the same as the default language),
1039  // but we make the link target be the one site-wide page.
1040  $title = Title::newFromText( $this->msg( $page )->inContentLanguage()->text() );
1041 
1042  return $title ?: null;
1043  }
1044 
1049  function privacyLink() {
1050  return $this->footerLink( 'privacy', 'privacypage' );
1051  }
1052 
1057  function aboutLink() {
1058  return $this->footerLink( 'aboutsite', 'aboutpage' );
1059  }
1060 
1065  function disclaimerLink() {
1066  return $this->footerLink( 'disclaimers', 'disclaimerpage' );
1067  }
1068 
1076  function editUrlOptions() {
1077  $options = [ 'action' => 'edit' ];
1078 
1079  if ( !$this->isRevisionCurrent() ) {
1080  $options['oldid'] = intval( $this->getRevisionId() );
1081  }
1082 
1083  return $options;
1084  }
1085 
1090  function showEmailUser( $id ) {
1091  if ( $id instanceof User ) {
1092  $targetUser = $id;
1093  } else {
1094  $targetUser = User::newFromId( $id );
1095  }
1096 
1097  # The sending user must have a confirmed email address and the receiving
1098  # user must accept emails from the sender.
1099  return $this->getUser()->canSendEmail()
1100  && SpecialEmailUser::validateTarget( $targetUser, $this->getUser() ) === '';
1101  }
1102 
1114  function getSkinStylePath( $name ) {
1115  global $wgStylePath;
1116 
1117  if ( $this->stylename === null ) {
1118  $class = static::class;
1119  throw new MWException( "$class::\$stylename must be set to use getSkinStylePath()" );
1120  }
1121 
1122  return "$wgStylePath/{$this->stylename}/$name";
1123  }
1124 
1125  /* these are used extensively in SkinTemplate, but also some other places */
1126 
1131  static function makeMainPageUrl( $urlaction = '' ) {
1133  self::checkTitle( $title, '' );
1134 
1135  return $title->getLinkURL( $urlaction );
1136  }
1137 
1149  static function makeSpecialUrl( $name, $urlaction = '', $proto = null ) {
1151  if ( is_null( $proto ) ) {
1152  return $title->getLocalURL( $urlaction );
1153  } else {
1154  return $title->getFullURL( $urlaction, false, $proto );
1155  }
1156  }
1157 
1164  static function makeSpecialUrlSubpage( $name, $subpage, $urlaction = '' ) {
1165  $title = SpecialPage::getSafeTitleFor( $name, $subpage );
1166  return $title->getLocalURL( $urlaction );
1167  }
1168 
1174  static function makeI18nUrl( $name, $urlaction = '' ) {
1175  $title = Title::newFromText( wfMessage( $name )->inContentLanguage()->text() );
1176  self::checkTitle( $title, $name );
1177  return $title->getLocalURL( $urlaction );
1178  }
1179 
1185  static function makeUrl( $name, $urlaction = '' ) {
1187  self::checkTitle( $title, $name );
1188 
1189  return $title->getLocalURL( $urlaction );
1190  }
1191 
1198  static function makeInternalOrExternalUrl( $name ) {
1199  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $name ) ) {
1200  return $name;
1201  } else {
1202  return self::makeUrl( $name );
1203  }
1204  }
1205 
1213  static function makeNSUrl( $name, $urlaction = '', $namespace = NS_MAIN ) {
1214  $title = Title::makeTitleSafe( $namespace, $name );
1215  self::checkTitle( $title, $name );
1216 
1217  return $title->getLocalURL( $urlaction );
1218  }
1219 
1226  static function makeUrlDetails( $name, $urlaction = '' ) {
1228  self::checkTitle( $title, $name );
1229 
1230  return [
1231  'href' => $title->getLocalURL( $urlaction ),
1232  'exists' => $title->isKnown(),
1233  ];
1234  }
1235 
1242  static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1244  self::checkTitle( $title, $name );
1245 
1246  return [
1247  'href' => $title->getLocalURL( $urlaction ),
1248  'exists' => true
1249  ];
1250  }
1251 
1258  static function checkTitle( &$title, $name ) {
1259  if ( !is_object( $title ) ) {
1261  if ( !is_object( $title ) ) {
1262  $title = Title::newFromText( '--error: link target missing--' );
1263  }
1264  }
1265  }
1266 
1288  public function buildSidebar() {
1290 
1291  $callback = function ( $old = null, &$ttl = null ) {
1292  $bar = [];
1293  $this->addToSidebar( $bar, 'sidebar' );
1294  Hooks::run( 'SkinBuildSidebar', [ $this, &$bar ] );
1295  if ( MessageCache::singleton()->isDisabled() ) {
1296  $ttl = WANObjectCache::TTL_UNCACHEABLE; // bug T133069
1297  }
1298 
1299  return $bar;
1300  };
1301 
1302  $msgCache = MessageCache::singleton();
1303  $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1304 
1305  $sidebar = $wgEnableSidebarCache
1306  ? $wanCache->getWithSetCallback(
1307  $wanCache->makeKey( 'sidebar', $this->getLanguage()->getCode() ),
1308  $wgSidebarCacheExpiry,
1309  $callback,
1310  [
1311  'checkKeys' => [
1312  // Unless there is both no exact $code override nor an i18n definition
1313  // in the software, the only MediaWiki page to check is for $code.
1314  $msgCache->getCheckKey( $this->getLanguage()->getCode() )
1315  ],
1316  'lockTSE' => 30
1317  ]
1318  )
1319  : $callback();
1320 
1321  // Apply post-processing to the cached value
1322  Hooks::run( 'SidebarBeforeOutput', [ $this, &$sidebar ] );
1323 
1324  return $sidebar;
1325  }
1326 
1336  public function addToSidebar( &$bar, $message ) {
1337  $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1338  }
1339 
1347  function addToSidebarPlain( &$bar, $text ) {
1348  $lines = explode( "\n", $text );
1349 
1350  $heading = '';
1351  $messageTitle = $this->getConfig()->get( 'EnableSidebarCache' )
1352  ? Title::newMainPage() : $this->getTitle();
1353 
1354  foreach ( $lines as $line ) {
1355  if ( strpos( $line, '*' ) !== 0 ) {
1356  continue;
1357  }
1358  $line = rtrim( $line, "\r" ); // for Windows compat
1359 
1360  if ( strpos( $line, '**' ) !== 0 ) {
1361  $heading = trim( $line, '* ' );
1362  if ( !array_key_exists( $heading, $bar ) ) {
1363  $bar[$heading] = [];
1364  }
1365  } else {
1366  $line = trim( $line, '* ' );
1367 
1368  if ( strpos( $line, '|' ) !== false ) { // sanity check
1369  $line = MessageCache::singleton()->transform( $line, false, null, $messageTitle );
1370  $line = array_map( 'trim', explode( '|', $line, 2 ) );
1371  if ( count( $line ) !== 2 ) {
1372  // Second sanity check, could be hit by people doing
1373  // funky stuff with parserfuncs... (T35321)
1374  continue;
1375  }
1376 
1377  $extraAttribs = [];
1378 
1379  $msgLink = $this->msg( $line[0] )->title( $messageTitle )->inContentLanguage();
1380  if ( $msgLink->exists() ) {
1381  $link = $msgLink->text();
1382  if ( $link == '-' ) {
1383  continue;
1384  }
1385  } else {
1386  $link = $line[0];
1387  }
1388  $msgText = $this->msg( $line[1] )->title( $messageTitle );
1389  if ( $msgText->exists() ) {
1390  $text = $msgText->text();
1391  } else {
1392  $text = $line[1];
1393  }
1394 
1395  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $link ) ) {
1396  $href = $link;
1397 
1398  // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1400  if ( $wgNoFollowLinks && !wfMatchesDomainList( $href, $wgNoFollowDomainExceptions ) ) {
1401  $extraAttribs['rel'] = 'nofollow';
1402  }
1403 
1404  global $wgExternalLinkTarget;
1405  if ( $wgExternalLinkTarget ) {
1406  $extraAttribs['target'] = $wgExternalLinkTarget;
1407  }
1408  } else {
1410 
1411  if ( $title ) {
1412  $title = $title->fixSpecialName();
1413  $href = $title->getLinkURL();
1414  } else {
1415  $href = 'INVALID-TITLE';
1416  }
1417  }
1418 
1419  $bar[$heading][] = array_merge( [
1420  'text' => $text,
1421  'href' => $href,
1422  'id' => Sanitizer::escapeIdForAttribute( 'n-' . strtr( $line[1], ' ', '-' ) ),
1423  'active' => false,
1424  ], $extraAttribs );
1425  } else {
1426  continue;
1427  }
1428  }
1429  }
1430 
1431  return $bar;
1432  }
1433 
1439  function getNewtalks() {
1440  $newMessagesAlert = '';
1441  $user = $this->getUser();
1442  $newtalks = $user->getNewMessageLinks();
1443  $out = $this->getOutput();
1444 
1445  // Allow extensions to disable or modify the new messages alert
1446  if ( !Hooks::run( 'GetNewMessagesAlert', [ &$newMessagesAlert, $newtalks, $user, $out ] ) ) {
1447  return '';
1448  }
1449  if ( $newMessagesAlert ) {
1450  return $newMessagesAlert;
1451  }
1452 
1453  if ( count( $newtalks ) == 1 && WikiMap::isCurrentWikiId( $newtalks[0]['wiki'] ) ) {
1454  $uTalkTitle = $user->getTalkPage();
1455  $lastSeenRev = $newtalks[0]['rev'] ?? null;
1456  $nofAuthors = 0;
1457  if ( $lastSeenRev !== null ) {
1458  $plural = true; // Default if we have a last seen revision: if unknown, use plural
1459  $latestRev = Revision::newFromTitle( $uTalkTitle, false, Revision::READ_NORMAL );
1460  if ( $latestRev !== null ) {
1461  // Singular if only 1 unseen revision, plural if several unseen revisions.
1462  $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1463  $nofAuthors = $uTalkTitle->countAuthorsBetween(
1464  $lastSeenRev, $latestRev, 10, 'include_new' );
1465  }
1466  } else {
1467  // Singular if no revision -> diff link will show latest change only in any case
1468  $plural = false;
1469  }
1470  $plural = $plural ? 999 : 1;
1471  // 999 signifies "more than one revision". We don't know how many, and even if we did,
1472  // the number of revisions or authors is not necessarily the same as the number of
1473  // "messages".
1474  $newMessagesLink = Linker::linkKnown(
1475  $uTalkTitle,
1476  $this->msg( 'newmessageslinkplural' )->params( $plural )->escaped(),
1477  [],
1478  $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1479  );
1480 
1481  $newMessagesDiffLink = Linker::linkKnown(
1482  $uTalkTitle,
1483  $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->escaped(),
1484  [],
1485  $lastSeenRev !== null
1486  ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1487  : [ 'diff' => 'cur' ]
1488  );
1489 
1490  if ( $nofAuthors >= 1 && $nofAuthors <= 10 ) {
1491  $newMessagesAlert = $this->msg(
1492  'youhavenewmessagesfromusers',
1493  $newMessagesLink,
1494  $newMessagesDiffLink
1495  )->numParams( $nofAuthors, $plural );
1496  } else {
1497  // $nofAuthors === 11 signifies "11 or more" ("more than 10")
1498  $newMessagesAlert = $this->msg(
1499  $nofAuthors > 10 ? 'youhavenewmessagesmanyusers' : 'youhavenewmessages',
1500  $newMessagesLink,
1501  $newMessagesDiffLink
1502  )->numParams( $plural );
1503  }
1504  $newMessagesAlert = $newMessagesAlert->text();
1505  # Disable CDN cache
1506  $out->setCdnMaxage( 0 );
1507  } elseif ( count( $newtalks ) ) {
1508  $sep = $this->msg( 'newtalkseparator' )->escaped();
1509  $msgs = [];
1510 
1511  foreach ( $newtalks as $newtalk ) {
1512  $msgs[] = Xml::element(
1513  'a',
1514  [ 'href' => $newtalk['link'] ], $newtalk['wiki']
1515  );
1516  }
1517  $parts = implode( $sep, $msgs );
1518  $newMessagesAlert = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped();
1519  $out->setCdnMaxage( 0 );
1520  }
1521 
1522  return $newMessagesAlert;
1523  }
1524 
1532  private function getCachedNotice( $name ) {
1533  global $wgRenderHashAppend;
1534 
1535  $needParse = false;
1536 
1537  if ( $name === 'default' ) {
1538  // special case
1539  global $wgSiteNotice;
1540  $notice = $wgSiteNotice;
1541  if ( empty( $notice ) ) {
1542  return false;
1543  }
1544  } else {
1545  $msg = $this->msg( $name )->inContentLanguage();
1546  if ( $msg->isBlank() ) {
1547  return '';
1548  } elseif ( $msg->isDisabled() ) {
1549  return false;
1550  }
1551  $notice = $msg->plain();
1552  }
1553 
1554  $services = MediaWikiServices::getInstance();
1555  $cache = $services->getMainWANObjectCache();
1556  $parsed = $cache->getWithSetCallback(
1557  // Use the extra hash appender to let eg SSL variants separately cache
1558  // Key is verified with md5 hash of unparsed wikitext
1559  $cache->makeKey( $name, $wgRenderHashAppend, md5( $notice ) ),
1560  // TTL in seconds
1561  600,
1562  function () use ( $notice ) {
1563  return $this->getOutput()->parseAsInterface( $notice );
1564  }
1565  );
1566 
1567  $contLang = $services->getContentLanguage();
1568  return Html::rawElement(
1569  'div',
1570  [
1571  'id' => 'localNotice',
1572  'lang' => $contLang->getHtmlCode(),
1573  'dir' => $contLang->getDir()
1574  ],
1575  $parsed
1576  );
1577  }
1578 
1584  function getSiteNotice() {
1585  $siteNotice = '';
1586 
1587  if ( Hooks::run( 'SiteNoticeBefore', [ &$siteNotice, $this ] ) ) {
1588  if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
1589  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1590  } else {
1591  $anonNotice = $this->getCachedNotice( 'anonnotice' );
1592  if ( $anonNotice === false ) {
1593  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1594  } else {
1595  $siteNotice = $anonNotice;
1596  }
1597  }
1598  if ( $siteNotice === false ) {
1599  $siteNotice = $this->getCachedNotice( 'default' );
1600  }
1601  }
1602 
1603  Hooks::run( 'SiteNoticeAfter', [ &$siteNotice, $this ] );
1604  return $siteNotice;
1605  }
1606 
1620  public function doEditSectionLink( Title $nt, $section, $tooltip, Language $lang ) {
1621  // HTML generated here should probably have userlangattributes
1622  // added to it for LTR text on RTL pages
1623 
1624  $attribs = [];
1625  if ( !is_null( $tooltip ) ) {
1626  $attribs['title'] = $this->msg( 'editsectionhint' )->rawParams( $tooltip )
1627  ->inLanguage( $lang )->text();
1628  }
1629 
1630  $links = [
1631  'editsection' => [
1632  'text' => $this->msg( 'editsection' )->inLanguage( $lang )->escaped(),
1633  'targetTitle' => $nt,
1634  'attribs' => $attribs,
1635  'query' => [ 'action' => 'edit', 'section' => $section ],
1636  'options' => [ 'noclasses', 'known' ]
1637  ]
1638  ];
1639 
1640  Hooks::run( 'SkinEditSectionLinks', [ $this, $nt, $section, $tooltip, &$links, $lang ] );
1641 
1642  $result = '<span class="mw-editsection"><span class="mw-editsection-bracket">[</span>';
1643 
1644  $linksHtml = [];
1645  foreach ( $links as $k => $linkDetails ) {
1646  $linksHtml[] = Linker::link(
1647  $linkDetails['targetTitle'],
1648  $linkDetails['text'],
1649  $linkDetails['attribs'],
1650  $linkDetails['query'],
1651  $linkDetails['options']
1652  );
1653  }
1654 
1655  $result .= implode(
1656  '<span class="mw-editsection-divider">'
1657  . $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
1658  . '</span>',
1659  $linksHtml
1660  );
1661 
1662  $result .= '<span class="mw-editsection-bracket">]</span></span>';
1663  return $result;
1664  }
1665 
1666 }
showEmailUser( $id)
Definition: Skin.php:1090
static makeUrlDetails( $name, $urlaction='')
these return an array with the &#39;href&#39; and boolean &#39;exists&#39;
Definition: Skin.php:1226
static makeI18nUrl( $name, $urlaction='')
Definition: Skin.php:1174
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method&#39;s arguments.
Definition: Skin.php:973
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:921
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:1996
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:785
footerLinkTitle( $desc, $page)
Definition: Skin.php:1031
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:2057
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:645
$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:352
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:897
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1439
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:1149
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:966
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:1288
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:1049
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:1620
initPage(OutputPage $out)
Definition: Skin.php:162
editUrlOptions()
Return URL options for the &#39;edit page&#39; link.
Definition: Skin.php:1076
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
getLogo()
URL to the logo.
Definition: Skin.php:498
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:57
getCopyrightIcon()
Definition: Skin.php:867
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:1532
$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:512
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:610
getSiteNotice()
Get the site notice.
Definition: Skin.php:1584
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:1994
getPageClasses( $title)
TODO: document.
Definition: Skin.php:438
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:3043
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:490
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:1996
$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:265
footerLink( $desc, $page)
Returns an HTML link for use in the footer.
Definition: Skin.php:1014
$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:2221
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1258
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:1690
mainPageLink()
Gets the link to the wiki&#39;s main page.
Definition: Skin.php:999
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:1289
drawCategoryBrowser( $tree)
Render the array as a series of links.
Definition: Skin.php:587
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:343
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:749
getCategoryLinks()
Definition: Skin.php:519
disclaimerLink()
Gets the link to the wiki&#39;s general disclaimers page.
Definition: Skin.php:1065
$wgUseCategoryBrowser
Use experimental, DMOZ-like category browser.
$cache
Definition: mcc.php:33
getSearchLink()
Definition: Skin.php:805
$mRelevantUser
Definition: Skin.php:45
const NS_CATEGORY
Definition: Defines.php:78
static makeVariablesScript( $data, $nonce=null)
Definition: Skin.php:400
$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:1996
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:827
$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:1996
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:671
setRelevantTitle( $t)
Set the "relevant" title.
Definition: Skin.php:329
getHtmlElementAttributes()
Return values for <html> element.
Definition: Skin.php:474
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:936
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1418
$wgRightsPage
Override for copyright metadata.
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:364
$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:1057
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition: Skin.php:1347
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition: Skin.php:1336
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:948
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it&#39;s convenient to think so) ...
Definition: Skin.php:1242
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:3043
static makeUrl( $name, $urlaction='')
Definition: Skin.php:1185
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:702
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:608
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:310
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:319
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:1213
$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:821
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:720
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:276
$messages
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1198
getSkinStylePath( $name)
Return a fully resolved style path URL to images or styles stored in the current skin&#39;s folder...
Definition: Skin.php:1114
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:416
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:585
setupSkinUserCss(OutputPage $out)
Hook point for adding style modules to OutputPage.
Definition: Skin.php:429
static makeMainPageUrl( $urlaction='')
Definition: Skin.php:1131
$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:310
escapeSearchLink()
Definition: Skin.php:813
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:680
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:1487
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1164
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