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&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, '&', 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