1007225e5Sgerardnico<?php 2007225e5Sgerardnico 3c3437056SNickeau 4*04fd306cSNickeauuse ComboStrap\ExceptionNotFound; 5*04fd306cSNickeauuse ComboStrap\MarkupPath; 63dc080c1Sgerardnicouse ComboStrap\Site; 7007225e5Sgerardnico 8007225e5Sgerardnico/** 93dc080c1Sgerardnico * Add all canonical HTML metadata 103dc080c1Sgerardnico * 113dc080c1Sgerardnico * In 1.14. we keep the name of the class with canonical to be able to update 123dc080c1Sgerardnico * Above 1.15, in a release branch, you can just modify it 13007225e5Sgerardnico */ 14*04fd306cSNickeauclass action_plugin_combo_metacanonical extends DokuWiki_Action_Plugin 15007225e5Sgerardnico{ 16007225e5Sgerardnico 17007225e5Sgerardnico 183dc080c1Sgerardnico const APPLE_MOBILE_WEB_APP_TITLE_META = "apple-mobile-web-app-title"; 193dc080c1Sgerardnico const APPLICATION_NAME_META = "application-name"; 203dc080c1Sgerardnico 21*04fd306cSNickeau /** 22*04fd306cSNickeau * @throws ExceptionNotFound 23*04fd306cSNickeau */ 24*04fd306cSNickeau public static function getContextPageForHeadHtmlMeta(): MarkupPath 25*04fd306cSNickeau { 26*04fd306cSNickeau 27*04fd306cSNickeau try { 28*04fd306cSNickeau $page = MarkupPath::createFromRequestedPage(); 29*04fd306cSNickeau } catch (ExceptionNotFound $e) { 30*04fd306cSNickeau // $_SERVER['SCRIPT_NAME']== "/lib/exe/mediamanager.php" 31*04fd306cSNickeau // $ID is null 32*04fd306cSNickeau // Admin call for instance 33*04fd306cSNickeau throw new ExceptionNotFound("No requested page"); 34*04fd306cSNickeau } 35*04fd306cSNickeau 36*04fd306cSNickeau /** 37*04fd306cSNickeau * No metadata for slot page 38*04fd306cSNickeau */ 39*04fd306cSNickeau if ($page->isSlot()) { 40*04fd306cSNickeau throw new ExceptionNotFound("Secondary slot"); 41*04fd306cSNickeau } 42*04fd306cSNickeau 43*04fd306cSNickeau return $page; 44*04fd306cSNickeau } 45*04fd306cSNickeau 46007225e5Sgerardnico public function register(Doku_Event_Handler $controller) 47007225e5Sgerardnico { 4885e82846SNickeau /** 4985e82846SNickeau * https://www.dokuwiki.org/devel:event:tpl_metaheader_output 5085e82846SNickeau */ 513dc080c1Sgerardnico $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'htmlHeadMetadataProcessing', array()); 52c3437056SNickeau 53c3437056SNickeau 54007225e5Sgerardnico } 55007225e5Sgerardnico 563dc080c1Sgerardnico 573dc080c1Sgerardnico function htmlHeadMetadataProcessing($event) 58007225e5Sgerardnico { 59007225e5Sgerardnico 60*04fd306cSNickeau try { 61*04fd306cSNickeau $page = self::getContextPageForHeadHtmlMeta(); 62*04fd306cSNickeau } catch (ExceptionNotFound $e) { 639da76789Sgerardnico return; 649da76789Sgerardnico } 659da76789Sgerardnico 66007225e5Sgerardnico 67007225e5Sgerardnico /** 683dc080c1Sgerardnico * Add the canonical metadata value 69007225e5Sgerardnico */ 703dc080c1Sgerardnico $this->canonicalHeadMetadata($event, $page); 71007225e5Sgerardnico /** 723dc080c1Sgerardnico * Add the app name value 733dc080c1Sgerardnico */ 743dc080c1Sgerardnico $this->appNameMetadata($event, $page); 753dc080c1Sgerardnico 763dc080c1Sgerardnico } 773dc080c1Sgerardnico 783dc080c1Sgerardnico /** 793dc080c1Sgerardnico * Dokuwiki has already a canonical methodology 803dc080c1Sgerardnico * https://www.dokuwiki.org/canonical 813dc080c1Sgerardnico * 823dc080c1Sgerardnico */ 83*04fd306cSNickeau private function canonicalHeadMetadata($event, MarkupPath $page) 843dc080c1Sgerardnico { 853dc080c1Sgerardnico 863dc080c1Sgerardnico /** 873dc080c1Sgerardnico * Where do we pick the canonical URL 88007225e5Sgerardnico * Canonical from meta 89007225e5Sgerardnico * 90007225e5Sgerardnico * FYI: The creation of the link was extracted from 91007225e5Sgerardnico * {@link wl()} that call {@link idfilter()} that performs just a replacement 92007225e5Sgerardnico * Calling the wl function will not work because 93007225e5Sgerardnico * {@link wl()} use the constant DOKU_URL that is set before any test via getBaseURL(true) 94007225e5Sgerardnico */ 95c3437056SNickeau $canonicalUrl = $page->getAbsoluteCanonicalUrl(); 96007225e5Sgerardnico 97007225e5Sgerardnico /** 98007225e5Sgerardnico * Replace the meta entry 99007225e5Sgerardnico * 100007225e5Sgerardnico * First search the key of the meta array 101007225e5Sgerardnico */ 102007225e5Sgerardnico $canonicalKey = ""; 103007225e5Sgerardnico $canonicalRelArray = array("rel" => "canonical", "href" => $canonicalUrl); 104007225e5Sgerardnico foreach ($event->data['link'] as $key => $link) { 105007225e5Sgerardnico if ($link["rel"] == "canonical") { 106007225e5Sgerardnico $canonicalKey = $key; 107007225e5Sgerardnico } 108007225e5Sgerardnico } 109007225e5Sgerardnico if ($canonicalKey != "") { 110007225e5Sgerardnico // Update 111007225e5Sgerardnico $event->data['link'][$canonicalKey] = $canonicalRelArray; 112007225e5Sgerardnico } else { 113007225e5Sgerardnico // Add 114007225e5Sgerardnico $event->data['link'][] = $canonicalRelArray; 115007225e5Sgerardnico } 116007225e5Sgerardnico 117007225e5Sgerardnico /** 118007225e5Sgerardnico * Add the Og canonical meta 119007225e5Sgerardnico * https://developers.facebook.com/docs/sharing/webmasters/getting-started/versioned-link/ 120007225e5Sgerardnico */ 121007225e5Sgerardnico $canonicalOgKeyKey = ""; 122007225e5Sgerardnico $canonicalPropertyKey = "og:url"; 123007225e5Sgerardnico $canonicalOgArray = array("property" => $canonicalPropertyKey, "content" => $canonicalUrl); 124ebdc69ceSgerardnico // Search if the canonical property is already present 125007225e5Sgerardnico foreach ($event->data['meta'] as $key => $meta) { 126ebdc69ceSgerardnico if (array_key_exists("property", $meta)) { 127ebdc69ceSgerardnico /** 128ebdc69ceSgerardnico * We may have several properties 129ebdc69ceSgerardnico */ 130007225e5Sgerardnico if ($meta["property"] == $canonicalPropertyKey) { 131007225e5Sgerardnico $canonicalOgKeyKey = $key; 132007225e5Sgerardnico } 133007225e5Sgerardnico } 134ebdc69ceSgerardnico } 135007225e5Sgerardnico if ($canonicalOgKeyKey != "") { 136007225e5Sgerardnico // Update 137007225e5Sgerardnico $event->data['meta'][$canonicalOgKeyKey] = $canonicalOgArray; 138007225e5Sgerardnico } else { 139007225e5Sgerardnico // Add 140007225e5Sgerardnico $event->data['meta'][] = $canonicalOgArray; 141007225e5Sgerardnico } 1423dc080c1Sgerardnico } 1433dc080c1Sgerardnico 1443dc080c1Sgerardnico /** 1453dc080c1Sgerardnico * Add the following meta 1463dc080c1Sgerardnico * <meta name="apple-mobile-web-app-title" content="appName"> 1473dc080c1Sgerardnico * <meta name="application-name" content="appName"> 1483dc080c1Sgerardnico * 1493dc080c1Sgerardnico * @param $event 150*04fd306cSNickeau * @param MarkupPath $page 1513dc080c1Sgerardnico * @return void 1523dc080c1Sgerardnico */ 153*04fd306cSNickeau private function appNameMetadata($event, MarkupPath $page) 1543dc080c1Sgerardnico { 1553dc080c1Sgerardnico $applicationName = Site::getName(); 1563dc080c1Sgerardnico 1573dc080c1Sgerardnico $applicationMetaNameValues = [ 1583dc080c1Sgerardnico self::APPLE_MOBILE_WEB_APP_TITLE_META, 1593dc080c1Sgerardnico self::APPLICATION_NAME_META 1603dc080c1Sgerardnico ]; 1613dc080c1Sgerardnico $metaNameKeyProperty = "name"; 1623dc080c1Sgerardnico foreach ($applicationMetaNameValues as $applicationNameValue) { 1633dc080c1Sgerardnico 1643dc080c1Sgerardnico $appMobileWebAppTitle = array($metaNameKeyProperty => $applicationNameValue, "content" => $applicationName);; 1653dc080c1Sgerardnico try { 1663dc080c1Sgerardnico $metaKey = $this->getMetaArrayIndex($metaNameKeyProperty, $applicationNameValue, $event->data['meta']); 1673dc080c1Sgerardnico // Update 1683dc080c1Sgerardnico $event->data['meta'][$metaKey] = $appMobileWebAppTitle; 169*04fd306cSNickeau } catch (ExceptionNotFound $e) { 1703dc080c1Sgerardnico // Add 1713dc080c1Sgerardnico $event->data['meta'][] = $appMobileWebAppTitle; 1723dc080c1Sgerardnico } 1733dc080c1Sgerardnico } 1743dc080c1Sgerardnico 175007225e5Sgerardnico 176007225e5Sgerardnico } 177007225e5Sgerardnico 1783dc080c1Sgerardnico /** 179*04fd306cSNickeau * @throws \ComboStrap\ExceptionNotFound 1803dc080c1Sgerardnico */ 1810db54741Sgerardnico private function getMetaArrayIndex(string $keyToSearch, string $keyValueToSearch, $metas) 1823dc080c1Sgerardnico { 1833dc080c1Sgerardnico // Search if the canonical property is already present 1840db54741Sgerardnico foreach ($metas as $metaKey => $metaValue) { 1850db54741Sgerardnico if (array_key_exists($keyToSearch, $metaValue)) { 1863dc080c1Sgerardnico /** 1873dc080c1Sgerardnico * We may have several properties 1883dc080c1Sgerardnico */ 1890db54741Sgerardnico if ($metaValue[$keyToSearch] == $keyValueToSearch) { 1900db54741Sgerardnico return $metaKey; 1913dc080c1Sgerardnico } 1923dc080c1Sgerardnico } 1933dc080c1Sgerardnico } 194*04fd306cSNickeau throw new ExceptionNotFound("The meta key {$keyToSearch} with the value {$keyValueToSearch} was not found"); 1953dc080c1Sgerardnico } 1963dc080c1Sgerardnico 1973dc080c1Sgerardnico 198007225e5Sgerardnico} 199