canExist() ) { return false; } if ( $title->inNamespace( NS_FILE ) ) { return MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title ); } if ( !$title->exists() ) { // No page id to select from return false; } $dbr = wfGetDB( DB_REPLICA ); $fileName = $dbr->selectField( 'page_props', 'pp_value', [ 'pp_page' => $title->getArticleID(), 'pp_propname' => [ self::PROP_NAME, self::PROP_NAME_FREE ] ], __METHOD__, [ 'ORDER BY' => 'pp_propname' ] ); $file = false; if ( $fileName ) { $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $fileName ); } return $file; } /** * InfoAction hook handler, adds the page image to the info=action page * * @see https://www.mediawiki.org/wiki/Manual:Hooks/InfoAction * * @param IContextSource $context Context, used to extract the title of the page * @param array[] &$pageInfo Auxillary information about the page. */ public function onInfoAction( $context, &$pageInfo ) { global $wgThumbLimits; $imageFile = self::getPageImage( $context->getTitle() ); if ( !$imageFile ) { // The page has no image return; } $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup(); $thumbSetting = $userOptionsLookup->getOption( $context->getUser(), 'thumbsize' ); $thumbSize = $wgThumbLimits[$thumbSetting]; $thumb = $imageFile->transform( [ 'width' => $thumbSize ] ); if ( !$thumb ) { return; } $imageHtml = $thumb->toHtml( [ 'alt' => $imageFile->getTitle()->getText(), 'desc-link' => true, ] ); $pageInfo['header-basic'][] = [ $context->msg( 'pageimages-info-label' ), $imageHtml ]; } /** * ApiOpenSearchSuggest hook handler, enhances ApiOpenSearch results with this extension's data * * @param array[] &$results Array of results to add page images too */ public function onApiOpenSearchSuggest( &$results ) { global $wgPageImagesExpandOpenSearchXml; if ( !$wgPageImagesExpandOpenSearchXml || !count( $results ) ) { return; } $pageIds = array_keys( $results ); $data = self::getImages( $pageIds, 50 ); foreach ( $pageIds as $id ) { if ( isset( $data[$id]['thumbnail'] ) ) { $results[$id]['image'] = $data[$id]['thumbnail']; } else { $results[$id]['image'] = null; } } } /** * SpecialMobileEditWatchlist::images hook handler, adds images to mobile watchlist A-Z view * * @param IContextSource $context Context object. Ignored * @param array[] $watchlist Array of relevant pages on the watchlist, sorted by namespace * @param array[] &$images Array of images to populate */ public static function onSpecialMobileEditWatchlistImages( IContextSource $context, array $watchlist, array &$images ) { $ids = []; foreach ( $watchlist as $ns => $pages ) { foreach ( array_keys( $pages ) as $dbKey ) { $title = Title::makeTitle( $ns, $dbKey ); // Getting page ID here is safe because SpecialEditWatchlist::getWatchlistInfo() // uses LinkBatch $id = $title->getArticleID(); if ( $id ) { $ids[$id] = $dbKey; } } } $data = self::getImages( array_keys( $ids ) ); foreach ( $data as $id => $page ) { if ( isset( $page['pageimage'] ) ) { $images[ $page['ns'] ][ $ids[$id] ] = $page['pageimage']; } } } /** * Returns image information for pages with given ids * * @param int[] $pageIds * @param int $size * * @return array[] */ private static function getImages( array $pageIds, $size = 0 ) { $ret = []; foreach ( array_chunk( $pageIds, ApiBase::LIMIT_SML1 ) as $chunk ) { $request = [ 'action' => 'query', 'prop' => 'pageimages', 'piprop' => 'name', 'pageids' => implode( '|', $chunk ), 'pilimit' => 'max', ]; if ( $size ) { $request['piprop'] = 'thumbnail'; $request['pithumbsize'] = $size; } $api = new ApiMain( new FauxRequest( $request ) ); $api->execute(); $ret += (array)$api->getResult()->getResultData( [ 'query', 'pages' ], [ 'Strip' => 'base' ] ); } return $ret; } /** * @param OutputPage $out The page being output. * @param Skin $skin Skin object used to generate the page. Ignored */ public function onBeforePageDisplay( $out, $skin ): void { if ( !$out->getConfig()->get( 'PageImagesOpenGraph' ) ) { return; } $imageFile = self::getPageImage( $out->getContext()->getTitle() ); if ( !$imageFile ) { $fallback = $out->getConfig()->get( 'PageImagesOpenGraphFallbackImage' ); if ( $fallback ) { $out->addMeta( 'og:image', wfExpandUrl( $fallback, PROTO_CANONICAL ) ); } return; } // Open Graph protocol -- https://ogp.me/ // Multiple images are supported according to https://ogp.me/#array // See https://developers.facebook.com/docs/sharing/best-practices?locale=en_US#images // See T282065: WhatsApp expects an image <300kB foreach ( [ 1200, 800, 640 ] as $width ) { $thumb = $imageFile->transform( [ 'width' => $width ] ); if ( !$thumb ) { continue; } $out->addMeta( 'og:image', wfExpandUrl( $thumb->getUrl(), PROTO_CANONICAL ) ); $out->addMeta( 'og:image:width', strval( $thumb->getWidth() ) ); $out->addMeta( 'og:image:height', strval( $thumb->getHeight() ) ); } } }