aura.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <?php
  2. namespace Grav\Plugin\Aura;
  3. use Grav\Common\Flex\Types\Pages\PageObject;
  4. use Grav\Common\Grav;
  5. class Aura
  6. {
  7. private $org;
  8. private $website;
  9. public $webpage;
  10. private $person;
  11. private $grav;
  12. private $otherPresence = [
  13. 'facebook-url',
  14. 'instagram-url',
  15. 'linkedin-url',
  16. 'pinterest-url',
  17. 'youtube-url',
  18. 'wikipedia-url',
  19. 'website-url',
  20. ];
  21. /**
  22. * Initializes Aura variables for the page
  23. *
  24. * @param PageObject $page
  25. */
  26. public function __construct($page)
  27. {
  28. $this->grav = $cache = Grav::instance();
  29. $this->setOrg();
  30. $this->setWebsite();
  31. $this->setWebPage($page);
  32. $this->setAuthor($page);
  33. }
  34. public function generateOpenGraphMeta()
  35. {
  36. $data = [
  37. 'og:url' => $this->webpage->url,
  38. 'og:type' => $this->webpage->type,
  39. 'og:title' => $this->webpage->title,
  40. ];
  41. if ($this->webpage->description) {
  42. $data['og:description'] = $this->webpage->description;
  43. }
  44. if ($this->webpage->image) {
  45. $data['og:image'] = $this->webpage->image->url;
  46. $data['og:image:type'] = $this->webpage->image->type;
  47. $data['og:image:width'] = $this->webpage->image->width;
  48. $data['og:image:height'] = $this->webpage->image->height;
  49. }
  50. if ($this->grav['config']->get('plugins.aura.org-facebook-appid')) {
  51. $data['fb:app_id'] = $this->grav['config']->get('plugins.aura.org-facebook-appid');
  52. }
  53. if ($this->person) {
  54. $data['og:author'] = $this->person->name;
  55. } else {
  56. $data['og:author'] = $this->org->name;
  57. }
  58. foreach ($data as $property => $content) {
  59. $this->webpage->metadata[$property] = [
  60. 'property' => $property,
  61. 'content' => $content,
  62. ];
  63. }
  64. }
  65. public function generateTwitterMeta()
  66. {
  67. $data = [
  68. 'twitter:card' => 'summary_large_image',
  69. 'twitter:title' => $this->webpage->title,
  70. ];
  71. if ($this->webpage->description) {
  72. $data['twitter:description'] = $this->webpage->description;
  73. }
  74. if ($this->grav['config']->get('plugins.aura.org-twitter-user')) {
  75. $data['twitter:site'] = '@' . $this->grav['config']->get('plugins.aura.org-twitter-user');
  76. }
  77. if ($this->person && $this->person->twitterUser) {
  78. $data['twitter:creator'] = '@' . $this->person->twitterUser;
  79. } else {
  80. if ($this->grav['config']->get('plugins.aura.org-twitter-user')) {
  81. $data['twitter:creator'] = '@' . $this->grav['config']->get('plugins.aura.org-twitter-user');
  82. }
  83. }
  84. if ($this->webpage->image) {
  85. $data['twitter:image'] = $this->webpage->image->url;
  86. }
  87. foreach ($data as $name => $content) {
  88. $this->webpage->metadata[$name] = [
  89. 'name' => $name,
  90. 'content' => $content,
  91. ];
  92. }
  93. }
  94. public function generateLinkedInMeta()
  95. {
  96. $data = [
  97. 'article:published_time' => $this->webpage->datePublished,
  98. 'article:modified_time' => $this->webpage->dateModified,
  99. ];
  100. if ($this->person) {
  101. $data['article:author'] = $this->person->name;
  102. } else {
  103. $data['article:author'] = $this->org->name;
  104. }
  105. foreach ($data as $property => $content) {
  106. $this->webpage->metadata[$property] = [
  107. 'property' => $property,
  108. 'content' => $content,
  109. ];
  110. }
  111. }
  112. public function generateStructuredData()
  113. {
  114. $organization = [
  115. '@type' => 'Organization',
  116. '@id' => $this->org->id,
  117. 'name' => $this->org->name,
  118. 'url' => $this->org->url,
  119. ];
  120. $website = [
  121. '@type' => 'WebSite',
  122. '@id' => $this->website->id,
  123. 'url' => $this->website->url,
  124. 'name' => $this->website->name,
  125. 'publisher' => [
  126. '@id' => $this->org->id,
  127. ],
  128. ];
  129. $webpage = [
  130. '@type' => 'WebPage',
  131. '@id' => $this->webpage->id,
  132. 'url' => $this->webpage->url,
  133. 'inLanguage' => $this->webpage->language,
  134. 'name' => $this->webpage->title,
  135. 'isPartOf' => [
  136. '@id' => $this->website->id,
  137. ],
  138. 'datePublished' => $this->webpage->datePublished,
  139. 'dateModified' => $this->webpage->dateModified,
  140. ];
  141. // Add Organization sameAs (if defined)
  142. if ($this->org->sameAs) {
  143. $organization['sameAs'] = $this->org->sameAs;
  144. }
  145. // Add logo (if defined)
  146. if ($this->org->logo) {
  147. $organization['logo'] = [
  148. '@type' => 'ImageObject',
  149. '@id' => $this->org->logo->id,
  150. 'url' => $this->org->logo->url,
  151. 'width' => $this->org->logo->width,
  152. 'height' => $this->org->logo->height,
  153. 'caption' => $this->org->logo->caption,
  154. ];
  155. $organization['image'] = [
  156. '@id' => $this->org->logo->id,
  157. ];
  158. }
  159. // Add page description (if defined)
  160. if ($this->webpage->description) {
  161. $webpage['description'] = $this->webpage->description;
  162. }
  163. // Add page image (if defined)
  164. if ($this->webpage->image) {
  165. $webpageImage = [
  166. '@type' => 'ImageObject',
  167. '@id' => $this->webpage->image->id,
  168. 'url' => $this->webpage->image->url,
  169. 'width' => $this->webpage->image->width,
  170. 'height' => $this->webpage->image->height,
  171. 'caption' => $this->webpage->image->caption,
  172. ];
  173. $webpage['primaryImageOfPage'] = [
  174. '@id' => $this->webpage->image->id,
  175. ];
  176. }
  177. // Additional based on page type i.e. article
  178. if ($this->webpage->type == 'article') {
  179. $article = [
  180. '@type' => 'Article',
  181. '@id' => $this->webpage->url . '#article',
  182. 'isPartOf' => [
  183. '@id' => $this->webpage->id,
  184. ],
  185. 'headline' => $this->webpage->title,
  186. 'datePublished' => $this->webpage->datePublished,
  187. 'dateModified' => $this->webpage->dateModified,
  188. 'mainEntityOfPage' => [
  189. '@id' => $this->webpage->id,
  190. ],
  191. 'publisher' => [
  192. '@id' => $this->org->id,
  193. ],
  194. ];
  195. // Add Image
  196. if ($this->webpage->image) {
  197. $article['image'] = [
  198. '@id' => $this->webpage->image->id,
  199. ];
  200. }
  201. // Add Author
  202. if ($this->person) {
  203. // Use Person (if defined)
  204. $person = [
  205. '@type' => 'Person',
  206. '@id' => $this->person->id,
  207. 'name' => $this->person->name,
  208. ];
  209. // Add Person description (if defined)
  210. if ($this->person->description) {
  211. $person['description'] = $this->person->description;
  212. }
  213. // Add Person sameAs (if defined)
  214. if ($this->person->sameAs) {
  215. $person['sameAs'] = $this->person->sameAs;
  216. }
  217. // Add Person image (if defined)
  218. if ($this->person->image) {
  219. $person['image'] = [
  220. '@type' => 'ImageObject',
  221. '@id' => $this->person->image->id,
  222. 'url' => $this->person->image->url,
  223. 'width' => $this->person->image->width,
  224. 'height' => $this->person->image->height,
  225. 'caption' => $this->person->image->caption,
  226. ];
  227. }
  228. $article['author'] = [
  229. '@id' => $this->person->id,
  230. ];
  231. } else {
  232. // Use Organization
  233. $article['author'] = [
  234. '@id' => $this->org->id,
  235. ];
  236. }
  237. }
  238. // Build the empty structured data block
  239. $data = [
  240. '@context' => 'https://schema.org',
  241. '@graph' => [],
  242. ];
  243. // Add the elements in order
  244. $data['@graph'][] = $organization;
  245. $data['@graph'][] = $website;
  246. if (isset($webpageImage)) {
  247. $data['@graph'][] = $webpageImage;
  248. }
  249. $data['@graph'][] = $webpage;
  250. if (isset($article)) {
  251. $data['@graph'][] = $article;
  252. }
  253. if (isset($person)) {
  254. $data['@graph'][] = $person;
  255. }
  256. return json_encode($data, JSON_UNESCAPED_SLASHES);
  257. }
  258. /**
  259. * @return void
  260. */
  261. protected function setOrg(): void
  262. {
  263. $this->org = new Organization();
  264. $this->org->url = (string)$this->grav['config']->get('plugins.aura.org-url');
  265. $this->org->id = $this->org->url . '#organization';
  266. $this->org->name = $this->grav['config']->get('plugins.aura.org-name');
  267. // Org SameAs
  268. $sameAs = [];
  269. foreach ($this->otherPresence as $platform) {
  270. $key = 'plugins.aura.org-' . $platform;
  271. if ($this->grav['config']->get($key)) {
  272. $sameAs[] = $this->grav['config']->get($key);
  273. }
  274. }
  275. $key = 'plugins.aura.org-twitter-user';
  276. if ($this->grav['config']->get($key)) {
  277. $sameAs[] = 'https://twitter.com/' . $this->grav['config']->get($key);
  278. }
  279. if (!empty($sameAs)) {
  280. $this->org->sameAs = $sameAs;
  281. }
  282. $this->setOrgLogo();
  283. }
  284. /**
  285. * @return void
  286. */
  287. protected function setOrgLogo(): void
  288. {
  289. // Org Logo
  290. if ($this->grav['config']->get('plugins.aura.org-logo')) {
  291. $imageArray = $this->grav['config']->get('plugins.aura.org-logo');
  292. $firstImage = reset($imageArray);
  293. $imagePath = ROOT_DIR . $firstImage['path'];
  294. if (file_exists($imagePath)) {
  295. $size = getimagesize($imagePath);
  296. $this->org->logo = new Image();
  297. $this->org->logo->url = $this->grav['base_url_absolute'] . '/' . $firstImage['path'];
  298. $this->org->logo->id = $this->org->url . '#logo';
  299. $this->org->logo->width = $size[0];
  300. $this->org->logo->height = $size[1];
  301. $this->org->logo->caption = $this->org->name;
  302. $this->org->logo->type = $size['mime'];
  303. }
  304. }
  305. }
  306. /**
  307. * @return void
  308. */
  309. protected function setWebsite(): void
  310. {
  311. $this->website = new WebSite;
  312. $this->website->url = $this->grav['base_url_absolute'];
  313. $this->website->id = $this->website->url . '#website';
  314. $this->website->name = $this->grav['config']->get('site.title');
  315. }
  316. /**
  317. * @param PageObject $page
  318. *
  319. * @return mixed
  320. */
  321. protected function setWebPage($page)
  322. {
  323. $this->webpage = new WebPage;
  324. $this->webpage->url = $page->url(true);
  325. $this->webpage->id = $this->webpage->url . '#webpage';
  326. $this->webpage->title = $page->title() . ' | ' . $this->grav['config']->get('site.title');
  327. $header = $page->header();
  328. if (isset($header->aura['description']) && $header->aura['description'] != '') {
  329. $this->webpage->description = (string)$header->aura['description'];
  330. }
  331. if (isset($header->language) && $header->language != '') {
  332. $this->webpage->language = $header->language;
  333. } else {
  334. $this->webpage->language = $this->grav['language']->getActive();
  335. if (!$this->webpage->language) {
  336. $this->webpage->language = $this->grav['config']->get('site.default_lang');
  337. }
  338. }
  339. $datePublishedRaw = time();
  340. if ($page->publishDate()) {
  341. $datePublishedRaw = $page->publishDate();
  342. } elseif ($page->date()) {
  343. $datePublishedRaw = $page->date();
  344. } elseif ($page->modified()) {
  345. $datePublishedRaw = $page->modified();
  346. }
  347. $dateModifiedRaw = $page->modified() ? $page->modified() : time();
  348. $this->webpage->datePublished = date('c', $datePublishedRaw);
  349. $this->webpage->dateModified = date('c', $dateModifiedRaw);
  350. $this->setWebpageImage($page);
  351. if ((isset($header->aura['pagetype'])) && ($header->aura['pagetype'] != '')) {
  352. $this->webpage->type = $header->aura['pagetype'];
  353. }
  354. }
  355. /**
  356. * @param PageObject $page
  357. *
  358. * @return void
  359. */
  360. protected function setWebpageImage($page): void
  361. {
  362. $image = null;
  363. $header = $page->header();
  364. if (isset($header->aura['image']) && $header->aura['image'] !== '') {
  365. $image = $page->media()->images()[$header->aura['image']] ?? null;
  366. } elseif (isset($header->media_order) && $header->media_order !== '') {
  367. $images = explode(',', $header->media_order);
  368. if (is_array($images) && !empty($images)) {
  369. $image = $page->media()->images()[reset($images)] ?? null;
  370. }
  371. }
  372. if ($image !== null) {
  373. $url_data = array_merge(
  374. parse_url($this->grav->get('base_url_absolute')),
  375. parse_url($image->url())
  376. );
  377. $url = call_user_func(
  378. static function (array $parts) {
  379. return (isset($parts['scheme']) ? "{$parts['scheme']}:" : '') .
  380. ((isset($parts['user']) || isset($parts['host'])) ? '//' : '') .
  381. (isset($parts['user']) ? (string)($parts['user']) : '') .
  382. (isset($parts['pass']) ? ":{$parts['pass']}" : '') .
  383. (isset($parts['user']) ? '@' : '') .
  384. (isset($parts['host']) ? (string)($parts['host']) : '') .
  385. (isset($parts['port']) ? ":{$parts['port']}" : '') .
  386. (isset($parts['path']) ? (string)($parts['path']) : '') .
  387. (isset($parts['query']) ? "?{$parts['query']}" : '') .
  388. (isset($parts['fragment']) ? "#{$parts['fragment']}" : '');
  389. }, $url_data
  390. );
  391. $this->webpage->image = new Image();
  392. $this->webpage->image->id = $this->webpage->url . '#primaryimage';
  393. $this->webpage->image->caption = $this->webpage->title;
  394. $this->webpage->image->url = $url;
  395. $this->webpage->image->width = $image->get('width');
  396. $this->webpage->image->height = $image->get('height');
  397. $this->webpage->image->type = $image->get('mime');
  398. }
  399. }
  400. /**
  401. * @param PageObject $page
  402. */
  403. protected function setAuthor($page): void
  404. {
  405. if (!$this->grav['config']->get('plugins.aura-authors.enabled') || !isset($page->header()->aura['author'])) {
  406. return;
  407. }
  408. $authors = $this->grav['config']->get('plugins.aura-authors.authors');
  409. $key = array_search($page->header()->aura['author'], array_column($authors, 'label'));
  410. if ($key !== false) {
  411. $author = $authors[$key];
  412. $this->person = new Person();
  413. $this->person->id = $this->org->url . '#person/' . $author['label'];
  414. $this->person->name = $author['name'];
  415. $this->person->description = $author['description'];
  416. // Person SameAs
  417. $sameAs = [];
  418. foreach ($this->otherPresence as $platform) {
  419. $key = 'person-' . $platform;
  420. if (isset($author[$key]) && $author[$key] != '') {
  421. $sameAs[] = $author[$key];
  422. }
  423. }
  424. $key = 'person-twitter-user';
  425. if (isset($author[$key]) && $author[$key] != '') {
  426. $this->person->twitterUser = $author[$key];
  427. $sameAs[] = 'https://twitter.com/' . $author[$key];
  428. }
  429. if (!empty($sameAs)) {
  430. $this->person->sameAs = $sameAs;
  431. }
  432. // Person Image
  433. if (isset($author['image']) && !empty($author['image'])) {
  434. $firstImage = reset($author['image']);
  435. $imagePath = ROOT_DIR . $firstImage['path'];
  436. if (file_exists($imagePath)) {
  437. $size = getimagesize($imagePath);
  438. $this->person->image = new Image();
  439. $this->person->image->url = $this->grav['base_url_absolute'] . '/' . $firstImage['path'];
  440. $this->person->image->id = $this->org->url . '#personimage/' . $author['label'];
  441. $this->person->image->width = $size[0];
  442. $this->person->image->height = $size[1];
  443. $this->person->image->caption = $author['name'];
  444. $this->person->image->type = $size['mime'];
  445. }
  446. }
  447. }
  448. }
  449. }