164 $this->getMain()->setCacheMode(
'anon-public-user-private' );
167 $params = $this->extractRequestParams();
171 $this->requireMaxOneParameter( $params,
'page',
'pageid',
'oldid',
'text' );
172 $this->requireMaxOneParameter( $params,
'page',
'pageid',
'oldid',
'title' );
173 $this->requireMaxOneParameter( $params,
'page',
'pageid',
'oldid',
'revid' );
175 $text = $params[
'text'];
176 $title = $params[
'title'];
178 $titleProvided =
false;
182 $titleProvided =
true;
185 $page = $params[
'page'];
186 $pageid = $params[
'pageid'];
187 $oldid = $params[
'oldid'];
189 $model = $params[
'contentmodel'];
190 $format = $params[
'contentformat'];
192 $prop = array_fill_keys( $params[
'prop'],
true );
194 if ( isset( $params[
'section'] ) ) {
195 $this->section = $params[
'section'];
196 if ( !preg_match(
'/^((T-)?\d+|new)$/', $this->section ) ) {
197 $this->dieWithError(
'apierror-invalidsection' );
200 $this->section =
false;
210 $needContent = isset( $prop[
'wikitext'] ) ||
211 isset( $prop[
'parsetree'] ) || $params[
'generatexml'];
214 $result = $this->getResult();
216 if ( $oldid !==
null || $pageid !==
null || $page !==
null ) {
217 if ( $this->section ===
'new' ) {
218 $this->dieWithError(
'apierror-invalidparammix-parse-new-section',
'invalidparammix' );
220 if ( $oldid !==
null ) {
222 $rev = $this->revisionLookup->getRevisionById( $oldid );
224 $this->dieWithError( [
'apierror-nosuchrevid', $oldid ] );
227 $this->checkTitleUserPermissions( $rev->getPage(),
'read' );
229 if ( !$rev->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
231 [
'apierror-permissiondenied', $this->msg(
'action-deletedtext' ) ]
235 $revLinkTarget = $rev->getPageAsLinkTarget();
236 $titleObj = Title::newFromLinkTarget( $revLinkTarget );
238 $pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
239 list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
240 $p_result = $this->getParsedContent(
241 $pageObj, $popts, $suppressCache, $pageid, $rev, $needContent
244 if ( $params[
'redirects'] ) {
249 if ( $pageid !==
null ) {
250 $reqParams[
'pageids'] = $pageid;
251 $pageParams[
'pageid'] = $pageid;
253 $reqParams[
'titles'] = $page;
254 $pageParams[
'title'] = $page;
260 $redirValues = $pageSet->getRedirectTitlesAsResult( $this->getResult() );
262 foreach ( $pageSet->getRedirectTitles() as
$title ) {
263 $pageParams = [
'title' =>
$title->getFullText() ];
265 } elseif ( $pageid !==
null ) {
266 $pageParams = [
'pageid' => $pageid ];
268 $pageParams = [
'title' => $page ];
271 $pageObj = $this->getTitleOrPageId( $pageParams,
'fromdb' );
272 $titleObj = $pageObj->getTitle();
273 if ( !$titleObj->exists() ) {
274 $this->dieWithError(
'apierror-missingtitle' );
277 $this->checkTitleUserPermissions( $titleObj,
'read' );
280 if ( isset( $prop[
'revid'] ) ) {
281 $oldid = $pageObj->getLatest();
284 list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
285 $p_result = $this->getParsedContent(
286 $pageObj, $popts, $suppressCache, $pageid,
null, $needContent
290 $titleObj = Title::newFromText(
$title );
291 if ( !$titleObj || $titleObj->isExternal() ) {
294 $revid = $params[
'revid'];
295 if ( $revid !==
null ) {
296 $rev = $this->revisionLookup->getRevisionById( $revid );
298 $this->dieWithError( [
'apierror-nosuchrevid', $revid ] );
300 $pTitleObj = $titleObj;
301 $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
302 if ( $titleProvided ) {
303 if ( !$titleObj->equals( $pTitleObj ) ) {
304 $this->addWarning( [
'apierror-revwrongpage', $rev->getId(),
310 $titleProvided =
true;
314 if ( $titleObj->canExist() ) {
315 $pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
316 list( $popts, $reset ) = $this->makeParserOptions( $pageObj, $params );
320 $popts = ParserOptions::newCanonical( $this->
getContext() );
321 list( $popts, $reset ) = $this->tweakParserOptions( $popts, $titleObj, $params );
324 $textProvided = $text !==
null;
326 if ( !$textProvided ) {
327 if ( $titleProvided && ( $prop || $params[
'generatexml'] ) ) {
328 if ( $revid !==
null ) {
329 $this->addWarning(
'apiwarn-parse-revidwithouttext' );
331 $this->addWarning(
'apiwarn-parse-titlewithouttext' );
340 if ( $textProvided && !$titleProvided && $model ===
null ) {
342 $this->addWarning( [
'apiwarn-parse-nocontentmodel', $model ] );
346 $this->content = ContentHandler::makeContent( $text, $titleObj, $model, $format );
348 $this->dieWithException( $ex, [
349 'wrap' => ApiMessage::create(
'apierror-contentserializationexception',
'parseerror' )
353 if ( $this->section !==
false ) {
354 if ( $this->section ===
'new' ) {
356 if ( $params[
'sectiontitle'] !==
null && $params[
'sectiontitle'] !==
'' ) {
357 $this->content = $this->content->addSectionHeader( $params[
'sectiontitle'] );
360 $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
364 if ( $params[
'pst'] || $params[
'onlypst'] ) {
365 $this->pstContent = $this->contentTransformer->preSaveTransform(
372 if ( $params[
'onlypst'] ) {
375 $result_array[
'text'] = $this->pstContent->serialize( $format );
376 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'text';
377 if ( isset( $prop[
'wikitext'] ) ) {
378 $result_array[
'wikitext'] = $this->content->serialize( $format );
379 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'wikitext';
381 if ( $params[
'summary'] !==
null ||
382 ( $params[
'sectiontitle'] !==
null && $this->section ===
'new' )
384 $result_array[
'parsedsummary'] = $this->formatSummary( $titleObj, $params );
385 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsedsummary';
388 $result->addValue(
null, $this->getModuleName(), $result_array );
394 if ( $params[
'pst'] ) {
395 $p_result = $this->getContentParserOutput( $this->pstContent, $titleObj, $revid, $popts );
397 $p_result = $this->getContentParserOutput( $this->content, $titleObj, $revid, $popts );
403 $result_array[
'title'] = $titleObj->getPrefixedText();
404 $result_array[
'pageid'] = $pageid ?: $titleObj->getArticleID();
405 if ( $this->contentIsDeleted ) {
406 $result_array[
'textdeleted'] =
true;
408 if ( $this->contentIsSuppressed ) {
409 $result_array[
'textsuppressed'] =
true;
412 if ( isset( $params[
'useskin'] ) ) {
413 $skin = $this->skinFactory->makeSkin( Skin::normalizeKey( $params[
'useskin'] ) );
420 if ( $skin || isset( $prop[
'subtitle'] ) || isset( $prop[
'headhtml'] ) || isset( $prop[
'categorieshtml'] ) ) {
431 $context->setTitle( $titleObj );
434 $context->setWikiPage( $pageObj );
438 $context->setRequest(
new FauxRequest( [
'action' =>
'view' ] ) );
442 $context->setSkin( $skin );
444 $skin = $context->getSkin();
449 $context->setSkin( $context->getSkin() );
454 $outputPage->setArticleFlag(
true );
456 $outputPage->addParserOutputMetadata( $p_result );
457 if ( $this->content ) {
458 $outputPage->addContentOverride( $titleObj, $this->content );
460 $context->setOutput( $outputPage );
464 $outputPage->loadSkinModules( $skin );
467 $this->getHookRunner()->onApiParseMakeOutputPage( $this, $outputPage );
470 if ( $oldid !==
null ) {
471 $result_array[
'revid'] = (int)$oldid;
474 if ( $params[
'redirects'] && $redirValues !==
null ) {
475 $result_array[
'redirects'] = $redirValues;
478 if ( isset( $prop[
'text'] ) ) {
479 $result_array[
'text'] = $p_result->getText( [
480 'allowTOC' => !$params[
'disabletoc'],
481 'enableSectionEditLinks' => !$params[
'disableeditsection'],
482 'wrapperDivClass' => $params[
'wrapoutputclass'],
483 'deduplicateStyles' => !$params[
'disablestylededuplication'],
484 'skin' => $context ? $context->getSkin() :
null,
486 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'text';
488 $this->getHookRunner()->onOutputPageBeforeHTML( $context->getOutput(), $result_array[
'text'] );
492 if ( $params[
'summary'] !==
null ||
493 ( $params[
'sectiontitle'] !==
null && $this->section ===
'new' )
495 $result_array[
'parsedsummary'] = $this->formatSummary( $titleObj, $params );
496 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsedsummary';
499 if ( isset( $prop[
'langlinks'] ) ) {
501 $langlinks = $outputPage->getLanguageLinks();
503 $langlinks = $p_result->getLanguageLinks();
507 if ( $params[
'effectivelanglinks'] ) {
509 $this->getHookRunner()->onLanguageLinks( $titleObj, $langlinks, $linkFlags );
513 $result_array[
'langlinks'] = $this->formatLangLinks( $langlinks );
515 if ( isset( $prop[
'categories'] ) ) {
516 $result_array[
'categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
518 if ( isset( $prop[
'categorieshtml'] ) ) {
519 $result_array[
'categorieshtml'] = $outputPage->getSkin()->getCategories();
520 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'categorieshtml';
522 if ( isset( $prop[
'links'] ) ) {
523 $result_array[
'links'] = $this->formatLinks( $p_result->getLinks() );
525 if ( isset( $prop[
'templates'] ) ) {
526 $result_array[
'templates'] = $this->formatLinks( $p_result->getTemplates() );
528 if ( isset( $prop[
'images'] ) ) {
529 $result_array[
'images'] = array_keys( $p_result->getImages() );
531 if ( isset( $prop[
'externallinks'] ) ) {
532 $result_array[
'externallinks'] = array_keys( $p_result->getExternalLinks() );
534 if ( isset( $prop[
'sections'] ) ) {
535 $result_array[
'sections'] = $p_result->getSections();
537 if ( isset( $prop[
'parsewarnings'] ) ) {
538 $result_array[
'parsewarnings'] = $p_result->getWarnings();
540 if ( isset( $prop[
'parsewarningshtml'] ) ) {
541 $warnings = $p_result->getWarnings();
542 $warningsHtml = array_map(
static function ( $warning ) {
543 return (
new RawMessage(
'$1', [ $warning ] ) )->parse();
545 $result_array[
'parsewarningshtml'] = $warningsHtml;
548 if ( isset( $prop[
'displaytitle'] ) ) {
549 $result_array[
'displaytitle'] = $p_result->getDisplayTitle() !==
false
550 ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText();
553 if ( isset( $prop[
'subtitle'] ) ) {
554 $result_array[
'subtitle'] = $context->getSkin()->prepareSubtitle();
557 if ( isset( $prop[
'headitems'] ) ) {
559 $result_array[
'headitems'] = $this->formatHeadItems( $outputPage->getHeadItemsArray() );
561 $result_array[
'headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
565 if ( isset( $prop[
'headhtml'] ) ) {
566 $result_array[
'headhtml'] = $outputPage->headElement( $context->getSkin() );
567 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'headhtml';
570 if ( isset( $prop[
'modules'] ) ) {
572 $result_array[
'modules'] = $outputPage->getModules();
574 $result_array[
'modulescripts'] = [];
575 $result_array[
'modulestyles'] = $outputPage->getModuleStyles();
577 $result_array[
'modules'] = array_values( array_unique( $p_result->getModules() ) );
579 $result_array[
'modulescripts'] = [];
580 $result_array[
'modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
584 if ( isset( $prop[
'jsconfigvars'] ) ) {
585 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
586 $result_array[
'jsconfigvars'] = ApiResult::addMetadataToResultVars( $jsconfigvars );
589 if ( isset( $prop[
'encodedjsconfigvars'] ) ) {
590 $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
591 $result_array[
'encodedjsconfigvars'] = FormatJson::encode(
596 $result_array[ApiResult::META_SUBELEMENTS][] =
'encodedjsconfigvars';
599 if ( isset( $prop[
'modules'] ) &&
600 !isset( $prop[
'jsconfigvars'] ) && !isset( $prop[
'encodedjsconfigvars'] ) ) {
601 $this->addWarning(
'apiwarn-moduleswithoutvars' );
604 if ( isset( $prop[
'indicators'] ) ) {
606 $result_array[
'indicators'] = (array)$outputPage->getIndicators();
608 $result_array[
'indicators'] = (array)$p_result->getIndicators();
610 ApiResult::setArrayType( $result_array[
'indicators'],
'BCkvp',
'name' );
613 if ( isset( $prop[
'iwlinks'] ) ) {
614 $result_array[
'iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
617 if ( isset( $prop[
'wikitext'] ) ) {
618 $result_array[
'wikitext'] = $this->content->serialize( $format );
619 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'wikitext';
621 if ( $this->pstContent !==
null ) {
622 $result_array[
'psttext'] = $this->pstContent->serialize( $format );
623 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'psttext';
626 if ( isset( $prop[
'properties'] ) ) {
627 $result_array[
'properties'] = (array)$p_result->getProperties();
628 ApiResult::setArrayType( $result_array[
'properties'],
'BCkvp',
'name' );
631 if ( isset( $prop[
'limitreportdata'] ) ) {
632 $result_array[
'limitreportdata'] =
633 $this->formatLimitReportData( $p_result->getLimitReportData() );
635 if ( isset( $prop[
'limitreporthtml'] ) ) {
637 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'limitreporthtml';
640 if ( isset( $prop[
'parsetree'] ) || $params[
'generatexml'] ) {
642 $this->dieWithError(
'apierror-parsetree-notwikitext',
'notwikitext' );
647 $xml = $this->parser->preprocessToDom( $this->content->getText() )->__toString();
648 $result_array[
'parsetree'] = $xml;
649 $result_array[ApiResult::META_BC_SUBELEMENTS][] =
'parsetree';
655 'categories' =>
'cl',
659 'externallinks' =>
'el',
664 'indicators' =>
'ind',
665 'modulescripts' =>
'm',
666 'modulestyles' =>
'm',
667 'properties' =>
'pp',
668 'limitreportdata' =>
'lr',
669 'parsewarnings' =>
'pw',
670 'parsewarningshtml' =>
'pw',
672 $this->setIndexedTagNames( $result_array, $result_mapping );
673 $result->addValue(
null, $this->getModuleName(), $result_array );