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