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