MediaWiki REL1_32
CategoryTree.php
Go to the documentation of this file.
1<?php
30 public $mOptions = [];
31
35 public function __construct( $options ) {
36 global $wgCategoryTreeDefaultOptions;
37
38 // ensure default values and order of options.
39 // Order may become important, it may influence the cache key!
40 foreach ( $wgCategoryTreeDefaultOptions as $option => $default ) {
41 if ( isset( $options[$option] ) ) {
42 $this->mOptions[$option] = $options[$option];
43 } else {
44 $this->mOptions[$option] = $default;
45 }
46 }
47
48 $this->mOptions['mode'] = self::decodeMode( $this->mOptions['mode'] );
49
50 if ( $this->mOptions['mode'] == CategoryTreeMode::PARENTS ) {
51 // namespace filter makes no sense with CategoryTreeMode::PARENTS
52 $this->mOptions['namespaces'] = false;
53 }
54
55 $this->mOptions['hideprefix'] = self::decodeHidePrefix( $this->mOptions['hideprefix'] );
56 $this->mOptions['showcount'] = self::decodeBoolean( $this->mOptions['showcount'] );
57 $this->mOptions['namespaces'] = self::decodeNamespaces( $this->mOptions['namespaces'] );
58
59 if ( $this->mOptions['namespaces'] ) {
60 # automatically adjust mode to match namespace filter
61 if ( count( $this->mOptions['namespaces'] ) === 1
62 && $this->mOptions['namespaces'][0] == NS_CATEGORY ) {
63 $this->mOptions['mode'] = CategoryTreeMode::CATEGORIES;
64 } elseif ( !in_array( NS_FILE, $this->mOptions['namespaces'] ) ) {
65 $this->mOptions['mode'] = CategoryTreeMode::PAGES;
66 } else {
67 $this->mOptions['mode'] = CategoryTreeMode::ALL;
68 }
69 }
70 }
71
76 public function getOption( $name ) {
77 return $this->mOptions[$name];
78 }
79
83 private function isInverse() {
84 return $this->getOption( 'mode' ) == CategoryTreeMode::PARENTS;
85 }
86
91 private static function decodeNamespaces( $nn ) {
92 global $wgContLang;
93
94 if ( $nn === false || is_null( $nn ) ) {
95 return false;
96 }
97
98 if ( !is_array( $nn ) ) {
99 $nn = preg_split( '![\s#:|]+!', $nn );
100 }
101
102 $namespaces = [];
103
104 foreach ( $nn as $n ) {
105 if ( is_int( $n ) ) {
106 $ns = $n;
107 } else {
108 $n = trim( $n );
109 if ( $n === '' ) {
110 continue;
111 }
112
113 $lower = strtolower( $n );
114
115 if ( is_numeric( $n ) ) {
116 $ns = (int)$n;
117 } elseif ( $n == '-' || $n == '_' || $n == '*' || $lower == 'main' ) {
118 $ns = NS_MAIN;
119 } else {
120 $ns = $wgContLang->getNsIndex( $n );
121 }
122 }
123
124 if ( is_int( $ns ) ) {
125 $namespaces[] = $ns;
126 }
127 }
128
129 sort( $namespaces ); # get elements into canonical order
130 return $namespaces;
131 }
132
137 public static function decodeMode( $mode ) {
138 global $wgCategoryTreeDefaultOptions;
139
140 if ( is_null( $mode ) ) {
141 return $wgCategoryTreeDefaultOptions['mode'];
142 }
143 if ( is_int( $mode ) ) {
144 return $mode;
145 }
146
147 $mode = trim( strtolower( $mode ) );
148
149 if ( is_numeric( $mode ) ) {
150 return (int)$mode;
151 }
152
153 if ( $mode == 'all' ) {
154 $mode = CategoryTreeMode::ALL;
155 } elseif ( $mode == 'pages' ) {
157 } elseif ( $mode == 'categories' || $mode == 'sub' ) {
159 } elseif ( $mode == 'parents' || $mode == 'super' || $mode == 'inverse' ) {
161 } elseif ( $mode == 'default' ) {
162 $mode = $wgCategoryTreeDefaultOptions['mode'];
163 }
164
165 return (int)$mode;
166 }
167
174 public static function decodeBoolean( $value ) {
175 if ( is_null( $value ) ) {
176 return null;
177 }
178 if ( is_bool( $value ) ) {
179 return $value;
180 }
181 if ( is_int( $value ) ) {
182 return ( $value > 0 );
183 }
184
185 $value = trim( strtolower( $value ) );
186 if ( is_numeric( $value ) ) {
187 return ( (int)$value > 0 );
188 }
189
190 if ( $value == 'yes' || $value == 'y'
191 || $value == 'true' || $value == 't' || $value == 'on'
192 ) {
193 return true;
194 } elseif ( $value == 'no' || $value == 'n'
195 || $value == 'false' || $value == 'f' || $value == 'off'
196 ) {
197 return false;
198 } elseif ( $value == 'null' || $value == 'default' || $value == 'none' || $value == 'x' ) {
199 return null;
200 } else {
201 return false;
202 }
203 }
204
209 public static function decodeHidePrefix( $value ) {
210 global $wgCategoryTreeDefaultOptions;
211
212 if ( is_null( $value ) ) {
213 return $wgCategoryTreeDefaultOptions['hideprefix'];
214 }
215 if ( is_int( $value ) ) {
216 return $value;
217 }
218 if ( $value === true ) {
220 }
221 if ( $value === false ) {
223 }
224
225 $value = trim( strtolower( $value ) );
226
227 if ( $value == 'yes' || $value == 'y'
228 || $value == 'true' || $value == 't' || $value == 'on'
229 ) {
231 } elseif ( $value == 'no' || $value == 'n'
232 || $value == 'false' || $value == 'f' || $value == 'off'
233 ) {
235 } elseif ( $value == 'always' ) {
237 } elseif ( $value == 'never' ) {
239 } elseif ( $value == 'auto' ) {
241 } elseif ( $value == 'categories' || $value == 'category' || $value == 'smart' ) {
243 } else {
244 return $wgCategoryTreeDefaultOptions['hideprefix'];
245 }
246 }
247
252 public static function setHeaders( $outputPage ) {
253 # Add the modules
254 $outputPage->addModuleStyles( 'ext.categoryTree.css' );
255 $outputPage->addModules( 'ext.categoryTree' );
256 }
257
264 protected static function encodeOptions( $options, $enc ) {
265 if ( $enc == 'mode' || $enc == '' ) {
266 $opt = $options['mode'];
267 } elseif ( $enc == 'json' ) {
268 $opt = FormatJson::encode( $options );
269 } else {
270 throw new Exception( 'Unknown encoding for CategoryTree options: ' . $enc );
271 }
272
273 return $opt;
274 }
275
280 public function getOptionsAsCacheKey( $depth = null ) {
281 $key = "";
282
283 foreach ( $this->mOptions as $k => $v ) {
284 if ( is_array( $v ) ) {
285 $v = implode( '|', $v );
286 }
287 $key .= $k . ':' . $v . ';';
288 }
289
290 if ( !is_null( $depth ) ) {
291 $key .= ";depth=" . $depth;
292 }
293 return $key;
294 }
295
300 public function getOptionsAsJsStructure( $depth = null ) {
301 if ( $depth !== null ) {
303 $opt['depth'] = $depth;
304 $s = self::encodeOptions( $opt, 'json' );
305 } else {
306 $s = self::encodeOptions( $this->mOptions, 'json' );
307 }
308
309 return $s;
310 }
311
315 private function getOptionsAsUrlParameters() {
316 return http_build_query( $this->mOptions );
317 }
318
330 public function getTag( $parser, $category, $hideroot = false, $attr = [], $depth = 1,
331 $allowMissing = false
332 ) {
333 global $wgCategoryTreeDisableCache;
334
335 $category = trim( $category );
336 if ( $category === '' ) {
337 return false;
338 }
339
340 if ( $parser ) {
341 if ( $wgCategoryTreeDisableCache === true ) {
342 $parser->disableCache();
343 } elseif ( is_int( $wgCategoryTreeDisableCache ) ) {
344 $parser->getOutput()->updateCacheExpiry( $wgCategoryTreeDisableCache );
345 }
346 }
347
348 $title = self::makeTitle( $category );
349
350 if ( $title === false || $title === null ) {
351 return false;
352 }
353
354 if ( isset( $attr['class'] ) ) {
355 $attr['class'] .= ' CategoryTreeTag';
356 } else {
357 $attr['class'] = ' CategoryTreeTag';
358 }
359
360 $attr['data-ct-mode'] = $this->mOptions['mode'];
361 $attr['data-ct-options'] = $this->getOptionsAsJsStructure();
362
363 $html = '';
364 $html .= Html::openElement( 'div', $attr );
365
366 if ( !$allowMissing && !$title->getArticleID() ) {
367 $html .= Html::openElement( 'span', [ 'class' => 'CategoryTreeNotice' ] );
368 if ( $parser ) {
369 $html .= $parser->recursiveTagParse(
370 wfMessage( 'categorytree-not-found', $category )->plain() );
371 } else {
372 $html .= wfMessage( 'categorytree-not-found', $category )->parse();
373 }
374 $html .= Html::closeElement( 'span' );
375 } else {
376 if ( !$hideroot ) {
377 $html .= $this->renderNode( $title, $depth );
378 } else {
379 $html .= $this->renderChildren( $title, $depth );
380 }
381 }
382
383 $html .= Xml::closeElement( 'div' );
384
385 return $html;
386 }
387
394 public function renderChildren( $title, $depth = 1 ) {
395 global $wgCategoryTreeMaxChildren, $wgCategoryTreeUseCategoryTable;
396
397 if ( $title->getNamespace() != NS_CATEGORY ) {
398 // Non-categories can't have children. :)
399 return '';
400 }
401
403
404 $inverse = $this->isInverse();
405 $mode = $this->getOption( 'mode' );
406 $namespaces = $this->getOption( 'namespaces' );
407
408 $tables = [ 'page', 'categorylinks' ];
409 $fields = [ 'page_id', 'page_namespace', 'page_title',
410 'page_is_redirect', 'page_len', 'page_latest', 'cl_to',
411 'cl_from' ];
412 $where = [];
413 $joins = [];
414 $options = [ 'ORDER BY' => 'cl_type, cl_sortkey', 'LIMIT' => $wgCategoryTreeMaxChildren ];
415
416 if ( $inverse ) {
417 $joins['categorylinks'] = [ 'RIGHT JOIN', [
418 'cl_to = page_title', 'page_namespace' => NS_CATEGORY
419 ] ];
420 $where['cl_from'] = $title->getArticleID();
421 } else {
422 $joins['categorylinks'] = [ 'JOIN', 'cl_from = page_id' ];
423 $where['cl_to'] = $title->getDBkey();
424 $options['USE INDEX']['categorylinks'] = 'cl_sortkey';
425
426 # namespace filter.
427 if ( $namespaces ) {
428 // NOTE: we assume that the $namespaces array contains only integers!
429 // decodeNamepsaces makes it so.
430 $where['page_namespace'] = $namespaces;
431 } elseif ( $mode != CategoryTreeMode::ALL ) {
432 if ( $mode == CategoryTreeMode::PAGES ) {
433 $where['cl_type'] = [ 'page', 'subcat' ];
434 } else {
435 $where['cl_type'] = 'subcat';
436 }
437 }
438 }
439
440 # fetch member count if possible
441 $doCount = !$inverse && $wgCategoryTreeUseCategoryTable;
442
443 if ( $doCount ) {
444 $tables = array_merge( $tables, [ 'category' ] );
445 $fields = array_merge( $fields, [
446 'cat_id', 'cat_title', 'cat_subcats', 'cat_pages', 'cat_files'
447 ] );
448 $joins['category'] = [ 'LEFT JOIN', [
449 'cat_title = page_title', 'page_namespace' => NS_CATEGORY ]
450 ];
451 }
452
453 $res = $dbr->select( $tables, $fields, $where, __METHOD__, $options, $joins );
454
455 # collect categories separately from other pages
456 $categories = '';
457 $other = '';
458
459 foreach ( $res as $row ) {
460 # NOTE: in inverse mode, the page record may be null, because we use a right join.
461 # happens for categories with no category page (red cat links)
462 if ( $inverse && $row->page_title === null ) {
463 $t = Title::makeTitle( NS_CATEGORY, $row->cl_to );
464 } else {
465 # TODO: translation support; ideally added to Title object
466 $t = Title::newFromRow( $row );
467 }
468
469 $cat = null;
470
471 if ( $doCount && $row->page_namespace == NS_CATEGORY ) {
472 $cat = Category::newFromRow( $row, $t );
473 }
474
475 $s = $this->renderNodeInfo( $t, $cat, $depth - 1 );
476
477 if ( $row->page_namespace == NS_CATEGORY ) {
478 $categories .= $s;
479 } else {
480 $other .= $s;
481 }
482 }
483
484 return $categories . $other;
485 }
486
492 public function renderParents( $title ) {
493 global $wgCategoryTreeMaxChildren;
494
496
497 $res = $dbr->select(
498 'categorylinks',
499 [
500 'page_namespace' => NS_CATEGORY,
501 'page_title' => 'cl_to',
502 ],
503 [ 'cl_from' => $title->getArticleID() ],
504 __METHOD__,
505 [
506 'LIMIT' => $wgCategoryTreeMaxChildren,
507 'ORDER BY' => 'cl_to'
508 ]
509 );
510
511 $special = SpecialPage::getTitleFor( 'CategoryTree' );
512
513 $s = '';
514
515 foreach ( $res as $row ) {
516 $t = Title::newFromRow( $row );
517
518 $label = $t->getText();
519
520 $wikiLink = $special->getLocalURL( 'target=' . $t->getPartialURL() .
521 '&' . $this->getOptionsAsUrlParameters() );
522
523 if ( $s !== '' ) {
524 $s .= wfMessage( 'pipe-separator' )->escaped();
525 }
526
527 $s .= Xml::openElement( 'span', [ 'class' => 'CategoryTreeItem' ] );
528 $s .= Xml::element( 'a', [ 'class' => 'CategoryTreeLabel', 'href' => $wikiLink ], $label );
529 $s .= Xml::closeElement( 'span' );
530 }
531
532 return $s;
533 }
534
541 public function renderNode( $title, $children = 0 ) {
542 global $wgCategoryTreeUseCategoryTable;
543
544 if ( $wgCategoryTreeUseCategoryTable && $title->getNamespace() == NS_CATEGORY
545 && !$this->isInverse()
546 ) {
547 $cat = Category::newFromTitle( $title );
548 } else {
549 $cat = null;
550 }
551
552 return $this->renderNodeInfo( $title, $cat, $children );
553 }
554
563 public function renderNodeInfo( $title, $cat, $children = 0 ) {
564 $mode = $this->getOption( 'mode' );
565
566 $ns = $title->getNamespace();
567 $key = $title->getDBkey();
568
569 $hideprefix = $this->getOption( 'hideprefix' );
570
571 if ( $hideprefix == CategoryTreeHidePrefix::ALWAYS ) {
572 $hideprefix = true;
573 } elseif ( $hideprefix == CategoryTreeHidePrefix::AUTO ) {
574 $hideprefix = ( $mode == CategoryTreeMode::CATEGORIES );
575 } elseif ( $hideprefix == CategoryTreeHidePrefix::CATEGORIES ) {
576 $hideprefix = ( $ns == NS_CATEGORY );
577 } else {
578 $hideprefix = true;
579 }
580
581 // when showing only categories, omit namespace in label unless we explicitely defined the
582 // configuration setting
583 // patch contributed by Manuel Schneider <manuel.schneider@wikimedia.ch>, Bug 8011
584 if ( $hideprefix ) {
585 $label = $title->getText();
586 } else {
587 $label = $title->getPrefixedText();
588 }
589
590 $labelClass = 'CategoryTreeLabel ' . ' CategoryTreeLabelNs' . $ns;
591
592 if ( !$title->getArticleID() ) {
593 $labelClass .= ' new';
594 $wikiLink = $title->getLocalURL( 'action=edit&redlink=1' );
595 } else {
596 $wikiLink = $title->getLocalURL();
597 }
598
599 if ( $ns == NS_CATEGORY ) {
600 $labelClass .= ' CategoryTreeLabelCategory';
601 } else {
602 $labelClass .= ' CategoryTreeLabelPage';
603 }
604
605 if ( ( $ns % 2 ) > 0 ) {
606 $labelClass .= ' CategoryTreeLabelTalk';
607 }
608
609 $count = false;
610 $s = '';
611
612 # NOTE: things in CategoryTree.js rely on the exact order of tags!
613 # Specifically, the CategoryTreeChildren div must be the first
614 # sibling with nodeName = DIV of the grandparent of the expland link.
615
616 $s .= Xml::openElement( 'div', [ 'class' => 'CategoryTreeSection' ] );
617 $s .= Xml::openElement( 'div', [ 'class' => 'CategoryTreeItem' ] );
618
619 $attr = [ 'class' => 'CategoryTreeBullet' ];
620
621 if ( $ns == NS_CATEGORY ) {
622 if ( $cat ) {
623 if ( $mode == CategoryTreeMode::CATEGORIES ) {
624 $count = intval( $cat->getSubcatCount() );
625 } elseif ( $mode == CategoryTreeMode::PAGES ) {
626 $count = intval( $cat->getPageCount() ) - intval( $cat->getFileCount() );
627 } else {
628 $count = intval( $cat->getPageCount() );
629 }
630 }
631 if ( $count === 0 ) {
632 $bullet = wfMessage( 'categorytree-empty-bullet' )->escaped() . ' ';
633 $attr['class'] = 'CategoryTreeEmptyBullet';
634 } else {
635 $linkattr = [];
636
637 $linkattr[ 'class' ] = "CategoryTreeToggle";
638 $linkattr['data-ct-title'] = $key;
639
640 $tag = 'span';
641 if ( $children == 0 ) {
642 // Use ->plain() and htmlspecialchars() to ensure
643 // identical to what is done by JS, which does:
644 // $link.text( mw.msg( 'categorytree-expand-bullet' ) )
645 $txt = htmlspecialchars( wfMessage( 'categorytree-expand-bullet' )->plain() );
646 $linkattr[ 'data-ct-state' ] = 'collapsed';
647 } else {
648 $txt = htmlspecialchars( wfMessage( 'categorytree-collapse-bullet' )->plain() );
649 $linkattr[ 'data-ct-loaded' ] = true;
650 $linkattr[ 'data-ct-state' ] = 'expanded';
651 }
652
653 $bullet = Xml::openElement( $tag, $linkattr ) . $txt . Xml::closeElement( $tag ) . ' ';
654 }
655 } else {
656 $bullet = wfMessage( 'categorytree-page-bullet' )->escaped();
657 }
658 $s .= Xml::tags( 'span', $attr, $bullet ) . ' ';
659
660 $s .= Xml::element(
661 'a',
662 [
663 'class' => $labelClass,
664 'href' => $wikiLink,
665 'title' => $title->getPrefixedText()
666 ],
667 $label
668 );
669
670 if ( $count !== false && $this->getOption( 'showcount' ) ) {
671 $s .= self::createCountString( RequestContext::getMain(), $cat, $count );
672 }
673
674 $s .= Xml::closeElement( 'div' );
675 $s .= Xml::openElement(
676 'div',
677 [
678 'class' => 'CategoryTreeChildren',
679 'style' => $children > 0 ? "display:block" : "display:none"
680 ]
681 );
682
683 if ( $ns == NS_CATEGORY && $children > 0 ) {
684 $children = $this->renderChildren( $title, $children );
685 if ( $children == '' ) {
686 $s .= Xml::openElement( 'i', [ 'class' => 'CategoryTreeNotice' ] );
687 if ( $mode == CategoryTreeMode::CATEGORIES ) {
688 $s .= wfMessage( 'categorytree-no-subcategories' )->escaped();
689 } elseif ( $mode == CategoryTreeMode::PAGES ) {
690 $s .= wfMessage( 'categorytree-no-pages' )->escaped();
691 } elseif ( $mode == CategoryTreeMode::PARENTS ) {
692 $s .= wfMessage( 'categorytree-no-parent-categories' )->escaped();
693 } else {
694 $s .= wfMessage( 'categorytree-nothing-found' )->escaped();
695 }
696 $s .= Xml::closeElement( 'i' );
697 } else {
698 $s .= $children;
699 }
700 }
701
702 $s .= Xml::closeElement( 'div' );
703 $s .= Xml::closeElement( 'div' );
704
705 return $s;
706 }
707
715 public static function createCountString( IContextSource $context, $cat, $countMode ) {
716 global $wgContLang;
717
718 # Get counts, with conversion to integer so === works
719 # Note: $allCount is the total number of cat members,
720 # not the count of how many members are normal pages.
721 $allCount = $cat ? intval( $cat->getPageCount() ) : 0;
722 $subcatCount = $cat ? intval( $cat->getSubcatCount() ) : 0;
723 $fileCount = $cat ? intval( $cat->getFileCount() ) : 0;
724 $pages = $allCount - $subcatCount - $fileCount;
725
726 $attr = [
727 'title' => $context->msg( 'categorytree-member-counts' )
728 ->numParams( $subcatCount, $pages, $fileCount, $allCount, $countMode )->text(),
729 'dir' => $context->getLanguage()->getDir() # numbers and commas get messed up in a mixed dir env
730 ];
731
732 $s = $wgContLang->getDirMark() . ' ';
733
734 # Create a list of category members with only non-zero member counts
735 $memberNums = [];
736 if ( $subcatCount ) {
737 $memberNums[] = $context->msg( 'categorytree-num-categories' )
738 ->numParams( $subcatCount )->text();
739 }
740 if ( $pages ) {
741 $memberNums[] = $context->msg( 'categorytree-num-pages' )->numParams( $pages )->text();
742 }
743 if ( $fileCount ) {
744 $memberNums[] = $context->msg( 'categorytree-num-files' )
745 ->numParams( $fileCount )->text();
746 }
747 $memberNumsShort = $memberNums
748 ? $context->getLanguage()->commaList( $memberNums )
749 : $context->msg( 'categorytree-num-empty' )->text();
750
751 # Only $5 is actually used in the default message.
752 # Other arguments can be used in a customized message.
753 $s .= Xml::tags(
754 'span',
755 $attr,
756 $context->msg( 'categorytree-member-num' )
757 // Do not use numParams on params 1-4, as they are only used for customisation.
758 ->params( $subcatCount, $pages, $fileCount, $allCount, $memberNumsShort )
759 ->escaped()
760 );
761
762 return $s;
763 }
764
770 public static function makeTitle( $title ) {
771 $title = trim( $title );
772
773 if ( strval( $title ) === '' ) {
774 return null;
775 }
776
777 # The title must be in the category namespace
778 # Ignore a leading Category: if there is one
779 $t = Title::newFromText( $title, NS_CATEGORY );
780 if ( !$t || $t->getNamespace() != NS_CATEGORY || $t->getInterwiki() != '' ) {
781 // If we were given something like "Wikipedia:Foo" or "Template:",
782 // try it again but forced.
783 $title = "Category:$title";
784 $t = Title::newFromText( $title );
785 }
786 return $t;
787 }
788
795 public static function capDepth( $mode, $depth ) {
796 global $wgCategoryTreeMaxDepth;
797
798 if ( is_numeric( $depth ) ) {
799 $depth = intval( $depth );
800 } else {
801 return 1;
802 }
803
804 if ( is_array( $wgCategoryTreeMaxDepth ) ) {
805 $max = isset( $wgCategoryTreeMaxDepth[$mode] ) ? $wgCategoryTreeMaxDepth[$mode] : 1;
806 } elseif ( is_numeric( $wgCategoryTreeMaxDepth ) ) {
807 $max = $wgCategoryTreeMaxDepth;
808 } else {
809 wfDebug( 'CategoryTree::capDepth: $wgCategoryTreeMaxDepth is invalid.' );
810 $max = 1;
811 }
812
813 return min( $depth, $max );
814 }
815}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
$wgContLang
Definition Setup.php:809
Core functions for the CategoryTree extension, an AJAX based gadget to display the category structure...
static encodeOptions( $options, $enc)
renderParents( $title)
Returns a string with an HTML representation of the parents of the given category.
renderNodeInfo( $title, $cat, $children=0)
Returns a string with a HTML represenation of the given page.
renderNode( $title, $children=0)
Returns a string with a HTML represenation of the given page.
__construct( $options)
static decodeBoolean( $value)
Helper function to convert a string to a boolean value.
static decodeHidePrefix( $value)
static decodeMode( $mode)
getTag( $parser, $category, $hideroot=false, $attr=[], $depth=1, $allowMissing=false)
Custom tag implementation.
renderChildren( $title, $depth=1)
Returns a string with an HTML representation of the children of the given category.
getOptionsAsCacheKey( $depth=null)
getOption( $name)
static decodeNamespaces( $nn)
static makeTitle( $title)
Creates a Title object from a user provided (and thus unsafe) string.
static capDepth( $mode, $depth)
Internal function to cap depth.
getOptionsAsJsStructure( $depth=null)
static setHeaders( $outputPage)
Add ResourceLoader modules to the OutputPage object.
static createCountString(IContextSource $context, $cat, $countMode)
Create a string which format the page, subcat and file counts of a category.
$res
Definition database.txt:21
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition hooks.txt:1873
namespace and then decline to actually register it & $namespaces
Definition hooks.txt:964
either a plain
Definition hooks.txt:2105
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:2050
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition hooks.txt:2885
this hook is for auditing only RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition hooks.txt:1035
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:2062
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
const NS_FILE
Definition Defines.php:70
const NS_MAIN
Definition Defines.php:64
const NS_CATEGORY
Definition Defines.php:78
Interface for objects which can provide a MediaWiki context on request.
const DB_REPLICA
Definition defines.php:25