45 $this->
getMain()->setCacheMode(
'anon-public-user-private' );
56 $text = $params[
'text'];
59 $titleProvided =
false;
63 $titleProvided =
true;
66 $page = $params[
'page'];
67 $pageid = $params[
'pageid'];
68 $oldid = $params[
'oldid'];
70 $model = $params[
'contentmodel'];
71 $format = $params[
'contentformat'];
73 $prop = array_flip( $params[
'prop'] );
75 if ( isset( $params[
'section'] ) ) {
76 $this->section = $params[
'section'];
77 if ( !preg_match(
'/^((T-)?\d+|new)$/', $this->section ) ) {
81 $this->section =
false;
91 $needContent = isset( $prop[
'wikitext'] ) ||
92 isset( $prop[
'parsetree'] ) || $params[
'generatexml'];
97 if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
98 if ( $this->section ===
'new' ) {
99 $this->
dieWithError(
'apierror-invalidparammix-parse-new-section',
'invalidparammix' );
101 if ( !is_null( $oldid ) ) {
105 $this->
dieWithError( [
'apierror-nosuchrevid', $oldid ] );
109 if ( !$rev->userCan( RevisionRecord::DELETED_TEXT, $this->getUser() ) ) {
111 [
'apierror-permissiondenied', $this->
msg(
'action-deletedtext' ) ]
115 $titleObj = $rev->getTitle();
118 list( $popts, $reset, $suppressCache ) = $this->
makeParserOptions( $pageObj, $params );
120 $pageObj, $popts, $suppressCache, $pageid, $rev, $needContent
123 if ( $params[
'redirects'] ) {
127 if ( !is_null( $pageid ) ) {
128 $reqParams[
'pageids'] = $pageid;
130 $reqParams[
'titles'] = $page;
136 $redirValues = $pageSet->getRedirectTitlesAsResult( $this->
getResult() );
139 foreach ( $pageSet->getRedirectTitles() as
$title ) {
140 $to =
$title->getFullText();
142 $pageParams = [
'title' => $to ];
143 } elseif ( !is_null( $pageid ) ) {
144 $pageParams = [
'pageid' => $pageid ];
146 $pageParams = [
'title' => $page ];
150 $titleObj = $pageObj->getTitle();
151 if ( !$titleObj || !$titleObj->exists() ) {
158 if ( isset( $prop[
'revid'] ) ) {
159 $oldid = $pageObj->getLatest();
162 list( $popts, $reset, $suppressCache ) = $this->
makeParserOptions( $pageObj, $params );
164 $pageObj, $popts, $suppressCache, $pageid,
null, $needContent
169 if ( !$titleObj || $titleObj->isExternal() ) {
172 $revid = $params[
'revid'];
173 if ( $revid !==
null ) {
176 $this->
dieWithError( [
'apierror-nosuchrevid', $revid ] );
178 $pTitleObj = $titleObj;
179 $titleObj = $rev->getTitle();
180 if ( $titleProvided ) {
181 if ( !$titleObj->equals( $pTitleObj ) ) {
182 $this->
addWarning( [
'apierror-revwrongpage', $rev->getId(),
188 $titleProvided =
true;
192 if ( $titleObj->canExist() ) {
197 $pageObj = $article->getPage();
201 $textProvided = !is_null( $text );
203 if ( !$textProvided ) {
204 if ( $titleProvided && ( $prop || $params[
'generatexml'] ) ) {
205 if ( $revid !==
null ) {
206 $this->
addWarning(
'apiwarn-parse-revidwithouttext' );
208 $this->
addWarning(
'apiwarn-parse-titlewithouttext' );
217 if ( $textProvided && !$titleProvided && is_null( $model ) ) {
219 $this->
addWarning( [
'apiwarn-parse-nocontentmodel', $model ] );
226 'wrap' =>
ApiMessage::create(
'apierror-contentserializationexception',
'parseerror' )
230 if ( $this->section !==
false ) {
231 if ( $this->section ===
'new' ) {
233 if ( !is_null( $params[
'sectiontitle'] ) && $params[
'sectiontitle'] !==
'' ) {
234 $this->content = $this->content->addSectionHeader( $params[
'sectiontitle'] );
237 $this->content = $this->
getSectionContent( $this->content, $titleObj->getPrefixedText() );
241 if ( $params[
'pst'] || $params[
'onlypst'] ) {
242 $this->pstContent = $this->content->preSaveTransform( $titleObj, $this->
getUser(), $popts );
244 if ( $params[
'onlypst'] ) {
247 $result_array[
'text'] = $this->pstContent->serialize( $format );
249 if ( isset( $prop[
'wikitext'] ) ) {
250 $result_array[
'wikitext'] = $this->content->serialize( $format );
253 if ( !is_null( $params[
'summary'] ) ||
254 ( !is_null( $params[
'sectiontitle'] ) && $this->section ===
'new' )
256 $result_array[
'parsedsummary'] = $this->
formatSummary( $titleObj, $params );
260 $result->addValue(
null, $this->
getModuleName(), $result_array );
266 if ( $params[
'pst'] ) {
267 $p_result = $this->pstContent->getParserOutput( $titleObj, $revid, $popts );
269 $p_result = $this->content->getParserOutput( $titleObj, $revid, $popts );
275 $result_array[
'title'] = $titleObj->getPrefixedText();
276 $result_array[
'pageid'] = $pageid ?: $pageObj->getId();
277 if ( $this->contentIsDeleted ) {
278 $result_array[
'textdeleted'] =
true;
280 if ( $this->contentIsSuppressed ) {
281 $result_array[
'textsuppressed'] =
true;
284 if ( isset( $params[
'useskin'] ) ) {
285 $factory = MediaWikiServices::getInstance()->getSkinFactory();
292 if ( $skin || isset( $prop[
'headhtml'] ) || isset( $prop[
'categorieshtml'] ) ) {
316 $outputPage =
new OutputPage(
$context );
317 $outputPage->addParserOutputMetadata( $p_result );
318 if ( $this->content ) {
319 $outputPage->addContentOverride( $titleObj, $this->content );
325 $skin->setupSkinUserCss( $outputPage );
327 $outputPage->loadSkinModules( $skin );
330 Hooks::run(
'ApiParseMakeOutputPage', [ $this, $outputPage ] );
333 if ( !is_null( $oldid ) ) {
334 $result_array[
'revid'] = (int)$oldid;
337 if ( $params[
'redirects'] && !is_null( $redirValues ) ) {
338 $result_array[
'redirects'] = $redirValues;
341 if ( isset( $prop[
'text'] ) ) {
342 $result_array[
'text'] = $p_result->getText( [
343 'allowTOC' => !$params[
'disabletoc'],
344 'enableSectionEditLinks' => !$params[
'disableeditsection'],
345 'wrapperDivClass' => $params[
'wrapoutputclass'],
346 'deduplicateStyles' => !$params[
'disablestylededuplication'],
351 if ( !is_null( $params[
'summary'] ) ||
352 ( !is_null( $params[
'sectiontitle'] ) && $this->section ===
'new' )
354 $result_array[
'parsedsummary'] = $this->
formatSummary( $titleObj, $params );
358 if ( isset( $prop[
'langlinks'] ) ) {
360 $langlinks = $outputPage->getLanguageLinks();
362 $langlinks = $p_result->getLanguageLinks();
366 if ( $params[
'effectivelanglinks'] ) {
368 Hooks::run(
'LanguageLinks', [ $titleObj, &$langlinks, &$linkFlags ] );
374 if ( isset( $prop[
'categories'] ) ) {
377 if ( isset( $prop[
'categorieshtml'] ) ) {
378 $result_array[
'categorieshtml'] = $outputPage->getSkin()->getCategories();
381 if ( isset( $prop[
'links'] ) ) {
382 $result_array[
'links'] = $this->
formatLinks( $p_result->getLinks() );
384 if ( isset( $prop[
'templates'] ) ) {
385 $result_array[
'templates'] = $this->
formatLinks( $p_result->getTemplates() );
387 if ( isset( $prop[
'images'] ) ) {
388 $result_array[
'images'] = array_keys( $p_result->getImages() );
390 if ( isset( $prop[
'externallinks'] ) ) {
391 $result_array[
'externallinks'] = array_keys( $p_result->getExternalLinks() );
393 if ( isset( $prop[
'sections'] ) ) {
394 $result_array[
'sections'] = $p_result->getSections();
396 if ( isset( $prop[
'parsewarnings'] ) ) {
397 $result_array[
'parsewarnings'] = $p_result->getWarnings();
400 if ( isset( $prop[
'displaytitle'] ) ) {
401 $result_array[
'displaytitle'] = $p_result->getDisplayTitle() !==
false
402 ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText();
405 if ( isset( $prop[
'headitems'] ) ) {
407 $result_array[
'headitems'] = $this->
formatHeadItems( $outputPage->getHeadItemsArray() );
409 $result_array[
'headitems'] = $this->
formatHeadItems( $p_result->getHeadItems() );
413 if ( isset( $prop[
'headhtml'] ) ) {
414 $result_array[
'headhtml'] = $outputPage->headElement(
$context->
getSkin() );
418 if ( isset( $prop[
'modules'] ) ) {
420 $result_array[
'modules'] = $outputPage->getModules();
422 $result_array[
'modulescripts'] = [];
423 $result_array[
'modulestyles'] = $outputPage->getModuleStyles();
425 $result_array[
'modules'] = array_values( array_unique( $p_result->getModules() ) );
427 $result_array[
'modulescripts'] = [];
428 $result_array[
'modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
432 if ( isset( $prop[
'jsconfigvars'] ) ) {
433 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
437 if ( isset( $prop[
'encodedjsconfigvars'] ) ) {
438 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
447 if ( isset( $prop[
'modules'] ) &&
448 !isset( $prop[
'jsconfigvars'] ) && !isset( $prop[
'encodedjsconfigvars'] ) ) {
449 $this->
addWarning(
'apiwarn-moduleswithoutvars' );
452 if ( isset( $prop[
'indicators'] ) ) {
454 $result_array[
'indicators'] = (array)$outputPage->getIndicators();
456 $result_array[
'indicators'] = (array)$p_result->getIndicators();
461 if ( isset( $prop[
'iwlinks'] ) ) {
462 $result_array[
'iwlinks'] = $this->
formatIWLinks( $p_result->getInterwikiLinks() );
465 if ( isset( $prop[
'wikitext'] ) ) {
466 $result_array[
'wikitext'] = $this->content->serialize( $format );
468 if ( !is_null( $this->pstContent ) ) {
469 $result_array[
'psttext'] = $this->pstContent->serialize( $format );
473 if ( isset( $prop[
'properties'] ) ) {
474 $result_array[
'properties'] = (array)$p_result->getProperties();
478 if ( isset( $prop[
'limitreportdata'] ) ) {
479 $result_array[
'limitreportdata'] =
482 if ( isset( $prop[
'limitreporthtml'] ) ) {
487 if ( isset( $prop[
'parsetree'] ) || $params[
'generatexml'] ) {
489 $this->
dieWithError(
'apierror-parsetree-notwikitext',
'notwikitext' );
492 $parser = MediaWikiServices::getInstance()->getParser();
495 $xml = $parser->preprocessToDom( $this->content->getText() )->__toString();
496 $result_array[
'parsetree'] = $xml;
503 'categories' =>
'cl',
507 'externallinks' =>
'el',
512 'indicators' =>
'ind',
513 'modulescripts' =>
'm',
514 'modulestyles' =>
'm',
515 'properties' =>
'pp',
516 'limitreportdata' =>
'lr',
517 'parsewarnings' =>
'pw'
520 $result->addValue(
null, $this->
getModuleName(), $result_array );
533 $popts->enableLimitReport( !$params[
'disablepp'] && !$params[
'disablelimitreport'] );
534 $popts->setIsPreview( $params[
'preview'] || $params[
'sectionpreview'] );
535 $popts->setIsSectionPreview( $params[
'sectionpreview'] );
536 if ( $params[
'disabletidy'] ) {
537 $popts->setTidy(
false );
539 if ( $params[
'wrapoutputclass'] !==
'' ) {
540 $popts->setWrapOutputClass( $params[
'wrapoutputclass'] );
544 $suppressCache =
false;
546 [ $popts, $pageObj->
getTitle(), $params, $this, &$reset, &$suppressCache ] );
549 $suppressCache = $suppressCache || !$popts->isSafeToCache();
551 return [ $popts, $reset, $suppressCache ];
564 WikiPage $page, $popts, $suppressCache, $pageId, $rev, $getContent
566 $revId = $rev ? $rev->getId() :
null;
567 $isDeleted = $rev && $rev->isDeleted( RevisionRecord::DELETED_TEXT );
569 if ( $getContent || $this->section !==
false || $isDeleted ) {
571 $this->content = $rev->getContent( RevisionRecord::FOR_THIS_USER, $this->
getUser() );
572 if ( !$this->content ) {
573 $this->
dieWithError( [
'apierror-missingcontent-revid', $revId ] );
576 $this->content = $page->
getContent( RevisionRecord::FOR_THIS_USER, $this->
getUser() );
577 if ( !$this->content ) {
581 $this->contentIsDeleted = $isDeleted;
582 $this->contentIsSuppressed = $rev &&
583 $rev->isDeleted( RevisionRecord::DELETED_TEXT | RevisionRecord::DELETED_RESTRICTED );
586 if ( $this->section !==
false ) {
589 $pageId ===
null ? $page->
getTitle()->getPrefixedText() : $this->
msg(
'pageid', $pageId )
591 return $this->content->getParserOutput( $page->
getTitle(), $revId, $popts );
596 $pout = $this->content->getParserOutput( $page->
getTitle(), $revId, $popts );
621 $this->
dieWithError( [
'apierror-nosuchsection-what', $this->section, $what ],
'nosuchsection' );
624 $this->
dieWithError( [
'apierror-sectionsnotsupported-what', $what ],
'nosuchsection' );
639 $summary = $params[
'summary'] ??
'';
640 $sectionTitle = $params[
'sectiontitle'] ??
'';
642 if ( $this->section ===
'new' && ( $sectionTitle ===
'' || $summary ===
'' ) ) {
643 if ( $sectionTitle !==
'' ) {
644 $summary = $params[
'sectiontitle'];
646 if ( $summary !==
'' ) {
647 $summary =
wfMessage(
'newsectionsummary' )
648 ->rawParams( MediaWikiServices::getInstance()->getParser()
649 ->stripSectionName( $summary ) )
650 ->inContentLanguage()->text();
658 foreach ( $links as $link ) {
660 $bits = explode(
':', $link, 2 );
663 $entry[
'lang'] = $bits[0];
692 $db = $this->
getDB();
693 $res = $db->select( [
'page',
'page_props' ],
694 [
'page_title',
'pp_propname' ],
695 $lb->constructSet(
'page', $db ),
699 'LEFT JOIN', [
'pp_propname' =>
'hiddencat',
'pp_page = page_id' ]
703 foreach (
$res as $row ) {
704 $hiddencats[$row->page_title] = isset( $row->pp_propname );
707 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
709 foreach ( $links as $link => $sortkey ) {
711 $entry[
'sortkey'] = $sortkey;
714 if ( !isset( $hiddencats[$link] ) ) {
715 $entry[
'missing'] =
true;
720 $linkCache->addBadLinkObj(
$title );
721 if (
$title->isKnown() ) {
722 $entry[
'known'] =
true;
724 } elseif ( $hiddencats[$link] ) {
725 $entry[
'hidden'] =
true;
735 foreach ( $links as $ns => $nslinks ) {
736 foreach ( $nslinks as
$title => $id ) {
740 $entry[
'exists'] = $id != 0;
750 foreach ( $iw as $prefix => $titles ) {
751 foreach ( array_keys( $titles ) as
$title ) {
753 $entry[
'prefix'] = $prefix;
770 foreach ( $headItems as $tag =>
$content ) {
772 $entry[
'tag'] = $tag;
783 foreach ( $limitReportData as $name => $value ) {
785 $entry[
'name'] = $name;
786 if ( !is_array( $value ) ) {
790 $entry = array_merge( $entry, $value );
798 foreach ( $mapping as $key => $name ) {
799 if ( isset( $array[$key] ) ) {
819 'redirects' =>
false,
825 'images|externallinks|sections|revid|displaytitle|iwlinks|' .
826 'properties|parsewarnings',
843 'encodedjsconfigvars',
858 'headitems' =>
'apiwarn-deprecation-parse-headitems',
861 'wrapoutputclass' =>
'mw-parser-output',
864 'effectivelanglinks' => [
876 'disablelimitreport' =>
false,
877 'disableeditsection' =>
false,
882 'disablestylededuplication' =>
false,
891 'sectionpreview' =>
false,
892 'disabletoc' =>
false,
907 'action=parse&page=Project:Sandbox'
908 =>
'apihelp-parse-example-page',
909 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
910 =>
'apihelp-parse-example-text',
911 'action=parse&text={{PAGENAME}}&title=Test'
912 =>
'apihelp-parse-example-texttitle',
913 'action=parse&summary=Some+[[link]]&prop='
914 =>
'apihelp-parse-example-summary',
919 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#parse';