Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
38.10% covered (danger)
38.10%
16 / 42
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
PageHooks
38.10% covered (danger)
38.10%
16 / 42
20.00% covered (danger)
20.00%
1 / 5
68.38
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 onRevisionDataUpdates
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 overwritePageImageProp
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 onOutputPageAfterGetHeadLinksArray
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * @file
18 */
19
20declare( strict_types=1 );
21
22namespace MediaWiki\Extension\WikiSEO\Hooks;
23
24use Config;
25use DeferrableUpdate;
26use ExtensionRegistry;
27use Html;
28use MediaWiki\Extension\WikiSEO\DeferredDescriptionUpdate;
29use MediaWiki\Extension\WikiSEO\OverwritePageImageProp;
30use MediaWiki\Extension\WikiSEO\WikiSEO;
31use MediaWiki\Hook\BeforePageDisplayHook;
32use MediaWiki\Revision\RenderedRevision;
33use MediaWiki\Storage\Hook\RevisionDataUpdatesHook;
34use OutputPage;
35use ParserOutput;
36use Skin;
37use Title;
38
39/**
40 * Hooks to run relating the page
41 */
42class PageHooks implements BeforePageDisplayHook, RevisionDataUpdatesHook {
43    /**
44     * @var Config
45     */
46    private $mainConfig;
47
48    /**
49     * PageHooks constructor.
50     *
51     * @param Config $config
52     */
53    public function __construct( Config $config ) {
54        $this->mainConfig = $config;
55    }
56
57    /**
58     * Queries the page properties for WikiSEO data and adds it as meta tags
59     *
60     * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay
61     *
62     * @param OutputPage $out
63     * @param Skin $skin
64     */
65    public function onBeforePageDisplay( $out, $skin ): void {
66        $seo = new WikiSEO();
67        $seo->setMetadataFromPageProps( $out );
68        $seo->addMetadataToPage( $out );
69    }
70
71    /**
72     * If WikiSeoEnableAutoDescription is enabled _and_ no manual description was defined
73     * We'll push a deferred DescriptionUpdate
74     *
75     * @param Title $title
76     * @param RenderedRevision $renderedRevision
77     * @param DeferrableUpdate[] &$updates
78     * @return void
79     * @see DeferredDescriptionUpdate
80     */
81    public function onRevisionDataUpdates( $title, $renderedRevision, &$updates ): void {
82        $output = $renderedRevision->getRevisionParserOutput();
83
84        if ( $output === null ) {
85            return;
86        }
87
88        $this->overwritePageImageProp( $title, $output, $updates );
89
90        $autoEnabled = $this->mainConfig->get( 'WikiSeoEnableAutoDescription' );
91
92        $currentDescription = $output->getPageProperty( 'description' );
93        $manualDescription = $output->getPageProperty( 'manualDescription' );
94
95        if ( !$autoEnabled || $manualDescription === true ) {
96            return;
97        }
98
99        $updates[] = new DeferredDescriptionUpdate(
100            $title,
101            $currentDescription !== false ? $currentDescription : null,
102            $this->mainConfig->get( 'WikiSeoTryCleanAutoDescription' )
103        );
104    }
105
106    /**
107     * Overwrite page prop 'page_imgaes_free' if PageImages is loaded and 'wgWikiSeoOverwritePageImage' is true
108     *
109     * @param Title $title
110     * @param ParserOutput $output
111     * @param array &$updates
112     * @return void
113     */
114    private function overwritePageImageProp( Title $title, ParserOutput $output, &$updates ) {
115        if ( !$this->mainConfig->get( 'WikiSeoOverwritePageImage' ) ||
116            $output->getPageProperty( 'image' ) === null ||
117            !ExtensionRegistry::getInstance()->isLoaded( 'PageImages' ) ) {
118            return;
119        }
120
121        $updates[] = new OverwritePageImageProp(
122            $title,
123            $output->getPageProperty( 'image' )
124        );
125    }
126
127    /**
128     * Sets, or overwrites, the '<link rel="canonical"' tag within the page HTML head,
129     * if the "canonical" parameter was set.
130     *
131     * @see https://www.mediawiki.org/wiki/Manual:Hooks/OutputPageAfterGetHeadLinksArray
132     *
133     * @param string[] &$tags
134     * @param OutputPage $output
135     */
136    public function onOutputPageAfterGetHeadLinksArray( &$tags, OutputPage $output ) {
137        $seo = new WikiSEO();
138        $seo->setMetadataFromPageProps( $output );
139        $canonicalTitle = $seo->getMetadataValue( 'canonical' );
140        if ( empty( $canonicalTitle ) ) {
141            return;
142        }
143
144        // Annoyingly, when MediaWiki adds a canonical link (when
145        // $wgEnableCanonicalServerLink is true), it uses a numeric
146        // key for it, rather than an obvious key like 'canonical'.
147        // So in order to overwrite it,
148        // we have to manually find this tag in the array.
149        $canonicalKey = 'canonical';
150        foreach ( $tags as $key => $tag ) {
151            if ( strpos( $tag, '<link rel="canonical"' ) !== false ) {
152                $canonicalKey = $key;
153                break;
154            }
155        }
156        $tags[$canonicalKey] = Html::element(
157            'link', [
158                'rel' => 'canonical',
159                'href' => $canonicalTitle
160            ]
161        );
162    }
163}