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