1<?php
2/**
3 * Semantic plugin: Add Schema.org News Article using JSON-LD
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
7 * @copyright  (C) 2015-2022, Giuseppe Di Terlizzi
8 */
9
10class helper_plugin_semantic extends DokuWiki_Plugin
11{
12
13    private $meta = array();
14    private $page = null;
15
16    /**
17     * Get Schema.org WebSite
18     *
19     * @return array
20     */
21    public function getWebSite()
22    {
23
24        global $conf;
25
26        $json_ld = array(
27            '@context'        => 'http://schema.org/',
28            '@type'           => 'WebSite',
29            'url'             => DOKU_URL,
30            'name'            => $conf['title'],
31            'potentialAction' => array(
32                '@type'       => 'SearchAction',
33                'target'      => DOKU_URL . DOKU_SCRIPT . '?do=search&amp;id={search_term_string}',
34                'query-input' => 'required name=search_term_string',
35            ),
36        );
37
38        return $json_ld;
39
40    }
41
42    /**
43     * Get the metadata of the page
44     *
45     * @param string $page ID
46     *
47     * @return string
48     */
49    public function getMetadata($page)
50    {
51
52        global $INFO;
53        global $ID;
54        global $license;
55        global $auth;
56        global $conf;
57
58        $this->page = cleanID($page);
59
60        $auth_check = auth_quickaclcheck($this->page);
61
62        if ((bool) preg_match('/' . trim($this->getConf('excludedPages')) . '/', $this->page)) {
63            return false;
64        }
65
66        if (!$auth_check) {
67            return false;
68        }
69
70        $this->meta = p_get_metadata($this->page);
71
72        if (isset($this->meta['plugin']['semantic']['enabled']) && !$this->meta['plugin']['semantic']['enabled']) {
73            return false;
74        }
75
76        if (!isset($this->meta['date']) || $this->meta['date'] == '') {
77            return false;
78        }
79
80        return $this->meta;
81
82    }
83
84    /**
85     * Get Schema.Org page type
86     *
87     * @return string
88     */
89    public function getSchemaOrgType()
90    {
91
92        return ((isset($this->meta['plugin']['semantic']['schema.org']['type']))
93            ? $this->meta['plugin']['semantic']['schema.org']['type']
94            : $this->getConf('defaultSchemaOrgType'));
95    }
96
97    /**
98     * Get the first image in page
99     *
100     * @return string
101     */
102    public function getFirstImage()
103    {
104        return (isset($this->meta['relation']['firstimage']) ? $this->meta['relation']['firstimage'] : null);
105    }
106
107    /**
108     * Get the URL of the first image in page
109     *
110     * @return string
111     */
112    public function getFirstImageURL()
113    {
114        return ($this->getFirstImage() ? ml($this->getFirstImage(), '', true, '&amp;', true) : null);
115    }
116
117    /**
118     * Get page description
119     *
120     * @return string
121     */
122    public function getDescription()
123    {
124        return (isset($this->meta['description']['abstract']) ? $this->meta['description']['abstract'] : $this->getTitle());
125    }
126
127    /**
128     * Get author name
129     *
130     * @return string
131     */
132    public function getAuthor()
133    {
134        return array_key_exists('creator', $this->meta) ? $this->meta['creator'] : null;
135    }
136
137    /**
138     * Get author ID
139     *
140     * @return string
141     */
142    public function getAuthorID()
143    {
144        return ($this->meta['user'] ? $this->meta['user'] : null);
145    }
146
147    /**
148     * Get the page title
149     *
150     * @return string
151     */
152    public function getTitle()
153    {
154        return (isset($this->meta['title']) ? $this->meta['title'] : null);
155    }
156
157    /**
158     * Get the create date of page
159     *
160     * @return int
161     */
162    public function getCreatedDate()
163    {
164        return (isset($this->meta['date']['created']) ? $this->meta['date']['created'] : -1);
165    }
166
167    /**
168     * Get the modified date of page
169     *
170     * @return int
171     */
172    public function getModifiedDate()
173    {
174        return (isset($this->meta['date']['modified']) ? $this->meta['date']['modified'] : -1);
175    }
176
177    /**
178     * Get DokuWiki license
179     *
180     * @return string
181     */
182    public function getLicense()
183    {
184        global $license;
185        global $conf;
186
187        return (isset($license[$conf['license']]) ? $license[$conf['license']] : null);
188    }
189
190    /**
191     * Return JSON-LD structured data in according of selected Schema.org type
192     *
193     * @return array
194     */
195    public function getStructuredData()
196    {
197
198        global $auth;
199        global $conf;
200
201        if (!count($this->meta)) {
202            return false;
203        }
204
205        $license        = $this->getLicense();
206        $type           = $this->getSchemaOrgType();
207        $user_data      = ($this->getConf('hideMail') ? array('mail' => null) : $auth->getUserData($this->getAuthorID()));
208        $license_url    = (($license !== null) and array_key_exists('url', $license)) ? $license['url'] : null;
209        $page_url       = wl($this->page, '', true);
210        $description    = str_replace("\n", ' ', $this->getDescription());
211        $created        = date(DATE_W3C, $this->getCreatedDate());
212        $modified       = date(DATE_W3C, $this->getModifiedDate());
213        $title          = (isset($this->meta['title']) ? $this->meta['title'] : $this->page);
214        $wiki_logo_info = array();
215        $wiki_logo      = tpl_getMediaFile(array(':wiki:logo.png', ':logo.png', 'images/logo.png'), true, $wiki_logo_info);
216
217        $json_ld = array(
218            '@context'         => 'http://schema.org/',
219            '@type'            => $type,
220            'headline'         => $title,
221            'name'             => $title,
222            'datePublished'    => $created,
223            'dateCreated'      => $created,
224            'dateModified'     => $modified,
225            'description'      => $description,
226            'license'          => $license_url,
227            'url'              => $page_url,
228
229            'mainEntityOfPage' => array(
230                '@type' => 'WebPage',
231                '@id'   => $page_url,
232            ),
233
234            'publisher'        => array(
235                '@type' => 'Organization',
236                'name'  => $conf['title'],
237                'logo'  => array(
238                    '@type' => 'ImageObject',
239                    'url'   => $wiki_logo,
240                ),
241            ),
242
243        );
244
245        if ($image_url = $this->getFirstImageURL()) {
246
247            $image_info    = array();
248            $article_image = tpl_getMediaFile(array(':' . $this->getFirstImage()), true, $image_info);
249
250            $json_ld['image'] = array(
251                '@type'  => 'ImageObject',
252                'url'    => $image_url,
253                'width'  => $image_info[0],
254                'height' => $image_info[1],
255            );
256
257        } else {
258
259            // Fallback
260            //$json_ld['image'] = $json_ld['publisher']['logo'];
261
262        }
263
264        if ($author = $this->getAuthor()) {
265
266            $json_ld['author'] = array(
267                '@context' => 'http://schema.org/',
268                '@type'    => 'Person',
269                'name'     => $author,
270                'email'    => $user_data['mail'],
271            );
272
273            if (isset($this->meta['contributor'])) {
274                foreach ($this->meta['contributor'] as $uid => $fullname) {
275
276                    $contributor_data = ($this->getConf('hideMail') ? array('mail' => null) : $auth->getUserData($uid));
277
278                    $json_ld['contributor'][] = array(
279                        '@context' => 'http://schema.org/',
280                        '@type'    => 'Person',
281                        'name'     => $fullname,
282                        'email'    => $contributor_data['mail'],
283                    );
284                }
285            }
286
287        }
288
289        return $json_ld;
290
291    }
292
293    public function getJsonLD()
294    {
295
296        $json_ld = array();
297
298        if ($structured_data = $this->getStructuredData()) {
299            $json_ld[] = $structured_data;
300        }
301
302        if ($backlinks = $this->getBacklinks()) {
303            $json_ld[] = $backlinks;
304        }
305
306        return $json_ld;
307
308    }
309
310    public function getBacklinks()
311    {
312
313        if (!$backlinks = ft_backlinks($this->page)) {
314            return false;
315        }
316
317        $json_ld_webpage = array(
318            '@context' => 'http://schema.org/',
319            '@type'    => 'WebPage',
320        );
321
322        foreach ($backlinks as $pageid) {
323            $json_ld_webpage['relatedLink'][] = wl($pageid, '', true);
324        }
325
326        if (isset($json_ld_webpage['relatedLink'])) {
327            return $json_ld_webpage;
328        }
329
330    }
331
332    public function getDublinCore()
333    {
334
335        global $conf;
336
337        if (!$this->meta) {
338            return array();
339        }
340
341        $license      = $this->getLicense();
342        $contributors = array();
343
344        if (isset($this->meta['contributor']) && is_array($this->meta['contributor'])) {
345            foreach ($this->meta['contributor'] as $uid => $fullname) {
346                $contributors[] = $fullname;
347            }
348        }
349
350        $dublin_core = array(
351            'DC.Title'        => $this->getTitle(),
352            'DC.Description'  => str_replace("\n", ' ', $this->getDescription()),
353            'DC.Publisher'    => $this->getAuthor(),
354            'DC.Contributors' => implode(', ', $contributors),
355            'DC.Rights'       => $license['name'],
356            'DC.Language'     => $conf['lang'],
357            'DC.Created'      => date(DATE_W3C, $this->getCreatedDate()),
358            'DC.Modified'     => date(DATE_W3C, $this->getModifiedDate()),
359            'DC.Date'         => date(DATE_W3C, $this->getCreatedDate()),
360            'DC.Identifier'   => "urn:" . $this->page,
361        );
362
363        return $dublin_core;
364
365    }
366
367    public function getOpenGraph()
368    {
369
370        global $conf;
371
372        if (!$this->meta) {
373            return array();
374        }
375
376        $locale = $conf['lang'];
377
378        if ($locale == 'en') {
379            $locale = 'en_GB';
380        } else {
381            $locale .= '_' . strtoupper($locale);
382        }
383
384        $open_graph = array(
385
386            'og:title'               => $this->getTitle(),
387            'og:description'         => str_replace("\n", ' ', $this->getDescription()),
388            'og:url'                 => wl($this->page, '', true),
389            'og:type'                => 'article',
390            'og:image'               => $this->getFirstImageURL(),
391            'og:locale'              => $locale,
392            'og:site_name'           => $conf['title'],
393
394            'article:published_time' => date(DATE_W3C, $this->getCreatedDate()),
395            'article:modified_time'  => date(DATE_W3C, $this->getModifiedDate()),
396            'article:section'        => date(DATE_W3C, $this->getModifiedDate()),
397            'article:author'         => $this->getAuthor(),
398
399        );
400
401        return $open_graph;
402
403    }
404
405}
406