206 $this->getMain()->setCacheMode(
'anon-public-user-private' );
209 $params = $this->extractRequestParams();
213 $this->requireMaxOneParameter(
$params,
'page',
'pageid',
'oldid',
'text' );
214 $this->requireMaxOneParameter(
$params,
'page',
'pageid',
'oldid',
'title' );
215 $this->requireMaxOneParameter(
$params,
'page',
'pageid',
'oldid',
'revid' );
219 if ( $title ===
null ) {
220 $titleProvided =
false;
224 $titleProvided =
true;
231 $prop = array_fill_keys(
$params[
'prop'],
true );
233 if ( isset(
$params[
'section'] ) ) {
234 $this->section =
$params[
'section'];
235 if ( !preg_match(
'/^((T-)?\d+|new)$/', $this->section ) ) {
236 $this->dieWithError(
'apierror-invalidsection' );
239 $this->section =
false;
250 $needContent = isset( $prop[
'wikitext'] ) ||
251 isset( $prop[
'parsetree'] ) ||
$params[
'generatexml'];
254 $result = $this->getResult();
256 if ( $oldid !==
null || $pageid !==
null || $page !==
null ) {
257 if ( $this->section ===
'new' ) {
258 $this->dieWithError(
'apierror-invalidparammix-parse-new-section',
'invalidparammix' );
260 if ( $oldid !==
null ) {
262 $rev = $this->revisionLookup->getRevisionById( $oldid );
264 $this->dieWithError( [
'apierror-nosuchrevid', $oldid ] );
267 $this->checkTitleUserPermissions( $rev->getPage(),
'read' );
269 if ( !$rev->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
271 [
'apierror-permissiondenied', $this->msg(
'action-deletedtext' ) ]
275 $revLinkTarget = $rev->getPageAsLinkTarget();
276 $titleObj = Title::newFromLinkTarget( $revLinkTarget );
278 $pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
279 [ $popts, $reset, $suppressCache ] = $this->makeParserOptions( $pageObj,
$params );
280 $p_result = $this->getParsedContent(
281 $pageObj, $popts, $suppressCache, $pageid, $rev, $needContent
289 if ( $pageid !==
null ) {
290 $reqParams[
'pageids'] = $pageid;
291 $pageParams[
'pageid'] = $pageid;
293 $reqParams[
'titles'] = $page;
294 $pageParams[
'title'] = $page;
300 $redirValues = $pageSet->getRedirectTitlesAsResult( $this->getResult() );
302 foreach ( $pageSet->getRedirectTargets() as $redirectTarget ) {
303 $pageParams = [
'title' => $this->titleFormatter->getFullText( $redirectTarget ) ];
305 } elseif ( $pageid !==
null ) {
306 $pageParams = [
'pageid' => $pageid ];
308 $pageParams = [
'title' => $page ];
311 $pageObj = $this->getTitleOrPageId( $pageParams,
'fromdb' );
313 if ( !$titleObj->exists() ) {
314 $this->dieWithError(
'apierror-missingtitle' );
317 $this->checkTitleUserPermissions( $titleObj,
'read' );
320 if ( isset( $prop[
'revid'] ) ) {
324 [ $popts, $reset, $suppressCache ] = $this->makeParserOptions( $pageObj,
$params );
325 $p_result = $this->getParsedContent(
326 $pageObj, $popts, $suppressCache, $pageid,
null, $needContent
330 $model =
$params[
'contentmodel'];
331 $format =
$params[
'contentformat'];
333 $titleObj = Title::newFromText( $title );
334 if ( !$titleObj || $titleObj->isExternal() ) {
335 $this->dieWithError( [
'apierror-invalidtitle',
wfEscapeWikiText( $title ) ] );
339 if ( $revid !==
null ) {
340 $rev = $this->revisionLookup->getRevisionById( $revid );
342 $this->dieWithError( [
'apierror-nosuchrevid', $revid ] );
344 $pTitleObj = $titleObj;
345 $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
346 if ( $titleProvided ) {
347 if ( !$titleObj->equals( $pTitleObj ) ) {
348 $this->addWarning( [
'apierror-revwrongpage', $rev->getId(),
354 $titleProvided =
true;
358 if ( $titleObj->canExist() ) {
359 $pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
360 [ $popts, $reset ] = $this->makeParserOptions( $pageObj,
$params );
364 $popts = ParserOptions::newFromContext( $this->
getContext() );
365 [ $popts, $reset ] = $this->tweakParserOptions( $popts, $titleObj,
$params );
368 $textProvided = $text !==
null;
370 if ( !$textProvided ) {
371 if ( $titleProvided && ( $prop ||
$params[
'generatexml'] ) ) {
372 if ( $revid !==
null ) {
373 $this->addWarning(
'apiwarn-parse-revidwithouttext' );
375 $this->addWarning(
'apiwarn-parse-titlewithouttext' );
384 if ( $textProvided && !$titleProvided && $model ===
null ) {
386 $this->addWarning( [
'apiwarn-parse-nocontentmodel', $model ] );
387 } elseif ( $model ===
null ) {
388 $model = $titleObj->getContentModel();
391 $contentHandler = $this->contentHandlerFactory->getContentHandler( $model );
393 if ( $format && !$contentHandler->isSupportedFormat( $format ) ) {
394 $this->dieWithError( [
'apierror-badformat-generic', $format, $model ] );
398 $this->content = $contentHandler->unserializeContent( $text, $format );
400 $this->dieWithException( $ex, [
401 'wrap' => ApiMessage::create(
'apierror-contentserializationexception',
'parseerror' )
405 if ( $this->section !==
false ) {
406 if ( $this->section ===
'new' ) {
408 if (
$params[
'sectiontitle'] !==
null ) {
409 $this->content = $this->content->addSectionHeader(
$params[
'sectiontitle'] );
412 $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
417 $this->pstContent = $this->contentTransformer->preSaveTransform(
420 $this->getUserForPreview(),
427 $result_array[
'text'] = $this->pstContent->serialize( $format );
428 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'text';
429 if ( isset( $prop[
'wikitext'] ) ) {
430 $result_array[
'wikitext'] = $this->content->serialize( $format );
431 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'wikitext';
433 if (
$params[
'summary'] !==
null ||
434 (
$params[
'sectiontitle'] !==
null && $this->section ===
'new' )
436 $result_array[
'parsedsummary'] = $this->formatSummary( $titleObj,
$params );
437 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsedsummary';
440 $result->addValue(
null, $this->getModuleName(), $result_array );
447 $p_result = $this->getContentParserOutput( $this->pstContent, $titleObj, $rev, $popts );
449 $p_result = $this->getContentParserOutput( $this->content, $titleObj, $rev, $popts );
455 $result_array[
'title'] = $titleObj->getPrefixedText();
456 $result_array[
'pageid'] = $pageid ?: $titleObj->getArticleID();
457 if ( $this->contentIsDeleted ) {
458 $result_array[
'textdeleted'] =
true;
460 if ( $this->contentIsSuppressed ) {
461 $result_array[
'textsuppressed'] =
true;
464 if ( isset(
$params[
'useskin'] ) ) {
473 $skin || isset( $prop[
'subtitle'] ) || isset( $prop[
'headhtml'] ) || isset( $prop[
'categorieshtml'] ) ||
474 isset(
$params[
'mobileformat'] )
490 $context->setTitle( $titleObj );
493 $context->setWikiPage( $pageObj );
497 $context->setRequest(
new FauxRequest( [
'action' =>
'view' ] ) );
501 $context->setSkin( $skin );
503 $skin = $context->getSkin();
508 $context->setSkin( $context->getSkin() );
513 $outputPage->setArticleFlag(
true );
515 $outputPage->addParserOutputMetadata( $p_result );
516 if ( $this->content ) {
517 $outputPage->addContentOverride( $titleObj, $this->content );
519 $context->setOutput( $outputPage );
523 $outputPage->loadSkinModules( $skin );
526 $this->getHookRunner()->onApiParseMakeOutputPage( $this, $outputPage );
529 if ( $oldid !==
null ) {
530 $result_array[
'revid'] = (int)$oldid;
533 if (
$params[
'redirects'] && $redirValues !==
null ) {
534 $result_array[
'redirects'] = $redirValues;
537 if ( isset( $prop[
'text'] ) ) {
538 $skin = $context ? $context->getSkin() :
null;
539 $skinOptions = $skin ? $skin->getOptions() : [
542 $result_array[
'text'] = $p_result->getText( [
543 'allowTOC' => !
$params[
'disabletoc'],
544 'injectTOC' => $skinOptions[
'toc'],
545 'enableSectionEditLinks' => !
$params[
'disableeditsection'],
546 'wrapperDivClass' =>
$params[
'wrapoutputclass'],
547 'deduplicateStyles' => !
$params[
'disablestylededuplication'],
548 'userLang' => $context ? $context->getLanguage() :
null,
550 'includeDebugInfo' => !
$params[
'disablepp'] && !
$params[
'disablelimitreport']
552 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'text';
554 $this->getHookRunner()->onOutputPageBeforeHTML( $context->getOutput(), $result_array[
'text'] );
558 if (
$params[
'summary'] !==
null ||
559 (
$params[
'sectiontitle'] !==
null && $this->section ===
'new' )
561 $result_array[
'parsedsummary'] = $this->formatSummary( $titleObj,
$params );
562 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsedsummary';
565 if ( isset( $prop[
'langlinks'] ) ) {
567 $langlinks = $outputPage->getLanguageLinks();
569 $langlinks = $p_result->getLanguageLinks();
573 if (
$params[
'effectivelanglinks'] ) {
575 $this->getHookRunner()->onLanguageLinks( $titleObj, $langlinks, $linkFlags );
579 $result_array[
'langlinks'] = $this->formatLangLinks( $langlinks );
581 if ( isset( $prop[
'categories'] ) ) {
582 $result_array[
'categories'] = $this->formatCategoryLinks( $p_result->getCategoryMap() );
584 if ( isset( $prop[
'categorieshtml'] ) ) {
585 $result_array[
'categorieshtml'] = $outputPage->getSkin()->getCategories();
586 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'categorieshtml';
588 if ( isset( $prop[
'links'] ) ) {
589 $result_array[
'links'] = $this->formatLinks( $p_result->getLinks() );
591 if ( isset( $prop[
'templates'] ) ) {
592 $result_array[
'templates'] = $this->formatLinks( $p_result->getTemplates() );
594 if ( isset( $prop[
'images'] ) ) {
597 $result_array[
'images'] = array_map(
598 fn ( $link ) => (
string)$link,
599 array_keys( $p_result->getImages() )
602 if ( isset( $prop[
'externallinks'] ) ) {
603 $result_array[
'externallinks'] = array_keys( $p_result->getExternalLinks() );
605 if ( isset( $prop[
'sections'] ) ) {
606 $result_array[
'sections'] = $p_result->getSections();
607 $result_array[
'showtoc'] = $p_result->getOutputFlag( ParserOutputFlags::SHOW_TOC );
609 if ( isset( $prop[
'parsewarnings'] ) ) {
610 $result_array[
'parsewarnings'] = $p_result->getWarnings();
612 if ( isset( $prop[
'parsewarningshtml'] ) ) {
613 $warnings = $p_result->getWarnings();
614 $warningsHtml = array_map(
static function ( $warning ) {
615 return (
new RawMessage(
'$1', [ $warning ] ) )->parse();
617 $result_array[
'parsewarningshtml'] = $warningsHtml;
620 if ( isset( $prop[
'displaytitle'] ) ) {
621 $result_array[
'displaytitle'] = $p_result->getDisplayTitle() !==
false
622 ? $p_result->getDisplayTitle()
623 : htmlspecialchars( $titleObj->getPrefixedText(), ENT_NOQUOTES );
626 if ( isset( $prop[
'subtitle'] ) ) {
628 $result_array[
'subtitle'] = $context->getSkin()->prepareSubtitle(
false );
631 if ( isset( $prop[
'headitems'] ) ) {
633 $result_array[
'headitems'] = $this->formatHeadItems( $outputPage->getHeadItemsArray() );
635 $result_array[
'headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
639 if ( isset( $prop[
'headhtml'] ) ) {
640 $result_array[
'headhtml'] = $outputPage->headElement( $context->getSkin() );
641 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'headhtml';
644 if ( isset( $prop[
'modules'] ) ) {
646 $result_array[
'modules'] = $outputPage->getModules();
648 $result_array[
'modulescripts'] = [];
649 $result_array[
'modulestyles'] = $outputPage->getModuleStyles();
651 $result_array[
'modules'] = array_values( array_unique( $p_result->getModules() ) );
653 $result_array[
'modulescripts'] = [];
654 $result_array[
'modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
658 if ( isset( $prop[
'jsconfigvars'] ) ) {
659 $showStrategyKeys = (bool)(
$params[
'showstrategykeys'] );
660 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars( $showStrategyKeys );
661 $result_array[
'jsconfigvars'] = ApiResult::addMetadataToResultVars( $jsconfigvars );
664 if ( isset( $prop[
'encodedjsconfigvars'] ) ) {
665 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
666 $result_array[
'encodedjsconfigvars'] = FormatJson::encode(
671 $result_array[ApiResult::META_SUBELEMENTS][] =
'encodedjsconfigvars';
674 if ( isset( $prop[
'modules'] ) &&
675 !isset( $prop[
'jsconfigvars'] ) && !isset( $prop[
'encodedjsconfigvars'] ) ) {
676 $this->addWarning(
'apiwarn-moduleswithoutvars' );
679 if ( isset( $prop[
'indicators'] ) ) {
681 $result_array[
'indicators'] = $outputPage->getIndicators();
683 $result_array[
'indicators'] = $p_result->getIndicators();
685 ApiResult::setArrayType( $result_array[
'indicators'],
'BCkvp',
'name' );
688 if ( isset( $prop[
'iwlinks'] ) ) {
689 $result_array[
'iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
692 if ( isset( $prop[
'wikitext'] ) ) {
693 $result_array[
'wikitext'] = $this->content->serialize( $format );
694 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'wikitext';
696 if ( $this->pstContent !==
null ) {
697 $result_array[
'psttext'] = $this->pstContent->serialize( $format );
698 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'psttext';
701 if ( isset( $prop[
'properties'] ) ) {
702 $result_array[
'properties'] = $p_result->getPageProperties();
703 ApiResult::setArrayType( $result_array[
'properties'],
'BCkvp',
'name' );
706 if ( isset( $prop[
'limitreportdata'] ) ) {
707 $result_array[
'limitreportdata'] =
708 $this->formatLimitReportData( $p_result->getLimitReportData() );
710 if ( isset( $prop[
'limitreporthtml'] ) ) {
711 $result_array[
'limitreporthtml'] = EditPage::getPreviewLimitReport( $p_result );
712 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'limitreporthtml';
715 if ( isset( $prop[
'parsetree'] ) ||
$params[
'generatexml'] ) {
717 $this->dieWithError(
'apierror-parsetree-notwikitext',
'notwikitext' );
720 $parser = $this->parserFactory->getInstance();
721 $parser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
723 $xml = $parser->preprocessToDom( $this->content->getText() )->__toString();
724 $result_array[
'parsetree'] = $xml;
725 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsetree';
731 'categories' =>
'cl',
735 'externallinks' =>
'el',
740 'indicators' =>
'ind',
741 'modulescripts' =>
'm',
742 'modulestyles' =>
'm',
743 'properties' =>
'pp',
744 'limitreportdata' =>
'lr',
745 'parsewarnings' =>
'pw',
746 'parsewarningshtml' =>
'pw',
748 $this->setIndexedTagNames( $result_array, $result_mapping );
749 $result->addValue(
null, $this->getModuleName(), $result_array );