Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.43% covered (warning)
81.43%
57 / 70
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
OpenGraph
81.43% covered (warning)
81.43%
57 / 70
60.00% covered (warning)
60.00%
3 / 5
20.08
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 addMetadata
72.09% covered (warning)
72.09%
31 / 43
0.00% covered (danger)
0.00%
0 / 1
13.63
 getAllowedParameterNames
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addTitleMeta
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 addSiteName
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
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\Generator\Plugins;
23
24use Html;
25use MediaWiki\Extension\WikiSEO\Generator\AbstractBaseGenerator;
26use MediaWiki\Extension\WikiSEO\Generator\GeneratorInterface;
27use MediaWiki\Extension\WikiSEO\WikiSEO;
28use MediaWiki\MediaWikiServices;
29use OutputPage;
30
31/**
32 * OpenGraph metadata generator
33 *
34 * @package MediaWiki\Extension\WikiSEO\Generator\Plugins
35 */
36class OpenGraph extends AbstractBaseGenerator implements GeneratorInterface {
37    protected static $htmlElementPropertyKey = 'property';
38    protected static $htmlElementContentKey = 'content';
39
40    /**
41     * Valid Tags for this generator
42     *
43     * @var array
44     */
45    protected $tags = [
46        'author',
47        'description',
48        'image',
49        'image_width',
50        'image_height',
51        'image_alt',
52        'keywords',
53        'locale',
54        'modified_time',
55        'published_time',
56        'section',
57        'site_name',
58        'title',
59        'type',
60    ];
61
62    /**
63     * Tag name conversions for this generator
64     *
65     * @var array
66     */
67    protected $conversions = [
68        'image'        => 'og:image',
69        'image_width'  => 'og:image:width',
70        'image_height' => 'og:image:height',
71        'image_alt'    => 'og:image:alt',
72
73        'locale'      => 'og:locale',
74        'type'        => 'og:type',
75        'title'       => 'og:title',
76        'site_name'   => 'og:site_name',
77        'description' => 'og:description',
78
79        'author'         => 'article:author',
80        'modified_time'  => 'article:modified_time',
81        'published_time' => 'article:published_time',
82        'section'        => 'article:section',
83        'keywords'       => 'article:tag',
84    ];
85
86    /**
87     * Page title property name
88     *
89     * @var string
90     */
91    protected $titlePropertyName = 'og:title';
92
93    /**
94     * Initialize the generator with all metadata and the page to output the metadata onto
95     *
96     * @param array $metadata All metadata
97     * @param OutputPage $out The page to add the metadata to
98     *
99     * @return void
100     */
101    public function init( array $metadata, OutputPage $out ): void {
102        $this->metadata = $metadata;
103        $this->outputPage = $out;
104
105        $this->setFallbackImageIfEnabled();
106
107        $this->preprocessFileMetadata();
108        $this->setModifiedPublishedTime();
109    }
110
111    /**
112     * Add the metadata to the OutputPage
113     *
114     * @return void
115     */
116    public function addMetadata(): void {
117        $this->addTitleMeta();
118        $this->addSiteName();
119
120        if ( $this->outputPage->getTitle() !== null ) {
121            $url = $this->outputPage->getTitle()->getFullURL();
122
123            $url = WikiSEO::protocolizeUrl( $url, $this->outputPage->getRequest() );
124
125            $this->outputPage->addHeadItem(
126                'og:url', Html::element(
127                    'meta', [
128                        self::$htmlElementPropertyKey => 'og:url',
129                        self::$htmlElementContentKey  => $url,
130                    ]
131                )
132            );
133        }
134
135        $ogImageExists = false;
136        foreach ( $this->outputPage->getMetaTags() as $metaTag ) {
137            $name = array_shift( $metaTag );
138            if ( $name !== null && $name === 'og:image' ) {
139                $ogImageExists = true;
140                break;
141            }
142        }
143
144        foreach ( $this->tags as $tag ) {
145            if ( array_key_exists( $tag, $this->metadata ) ) {
146                $convertedTag = $this->conversions[$tag];
147
148                if ( $convertedTag === 'og:image' ) {
149                    if ( $this->getConfigValue( 'WikiSeoEnableSocialImages' ) ) {
150                        $this->metadata['image_width'] = $this->getConfigValue( 'WikiSeoSocialImageWidth' );
151                        $this->metadata['image_height'] = $this->getConfigValue( 'WikiSeoSocialImageHeight' );
152                        $this->metadata['image'] = MediaWikiServices::getInstance()->getUrlUtils()->expand(
153                            sprintf(
154                                '/rest.php/wikiseo/v1/socialmediaimage/%s',
155                                urlencode( ltrim( $this->outputPage->getTitle()->getLinkURL(), '/' ) )
156                            )
157                        );
158                    // If an og:image is set, and we are using the fallback image, we skip our image
159                    } elseif ( $ogImageExists && $this->fallbackImageActive ) {
160                        unset( $this->tags['image_width'], $this->tags['image_height'] );
161                        continue;
162                    }
163                }
164
165                $this->outputPage->addHeadItem(
166                    $convertedTag, Html::element(
167                        'meta', [
168                            self::$htmlElementPropertyKey => $convertedTag,
169                            self::$htmlElementContentKey  => $this->metadata[$tag]
170                        ]
171                    )
172                );
173            }
174        }
175    }
176
177    /**
178     * @inheritDoc
179     */
180    public function getAllowedParameterNames(): array {
181        return $this->tags;
182    }
183
184    /**
185     * Add a title meta attribute to the output
186     *
187     * @return void
188     */
189    protected function addTitleMeta(): void {
190        $title = $this->outputPage->getHTMLTitle();
191
192        if ( $this->outputPage->getTitle() !== null ) {
193            $title = $this->outputPage->getTitle()->getPrefixedText() ?? $this->metadata['title'] ?? $title;
194        }
195
196        $this->outputPage->addHeadItem(
197            $this->titlePropertyName, Html::element(
198                'meta', [
199                    self::$htmlElementPropertyKey => $this->titlePropertyName,
200                    self::$htmlElementContentKey => $title,
201                ]
202            )
203        );
204    }
205
206    /**
207     * Add the sitename as og:site_name
208     *
209     * @return void
210     */
211    private function addSiteName(): void {
212        $sitename = $this->getConfigValue( 'Sitename' );
213
214        if ( !isset( $this->metadata['site_name'] ) && $sitename !== null ) {
215            $this->outputPage->addHeadItem(
216                'og:site_name', Html::element(
217                    'meta', [
218                        self::$htmlElementPropertyKey => 'og:site_name',
219                        self::$htmlElementContentKey => $sitename,
220                    ]
221                )
222            );
223        }
224    }
225}