15f891b7eSNickeau<?php 25f891b7eSNickeau 3c3437056SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4c3437056SNickeau 51fa8c418SNickeauuse ComboStrap\DokuPath; 6*82a60d03SNickeauuse ComboStrap\ExceptionCombo; 71fa8c418SNickeauuse ComboStrap\Image; 85f891b7eSNickeauuse ComboStrap\LogUtility; 9c3437056SNickeauuse ComboStrap\Mime; 105f891b7eSNickeauuse ComboStrap\Page; 11c3437056SNickeauuse ComboStrap\PageImage; 12c3437056SNickeauuse ComboStrap\PageImageUsage; 13c3437056SNickeauuse ComboStrap\PageType; 14c3437056SNickeauuse ComboStrap\PluginUtility; 155f891b7eSNickeauuse ComboStrap\Site; 165f891b7eSNickeauuse ComboStrap\StringUtility; 175f891b7eSNickeau 185f891b7eSNickeau 195f891b7eSNickeau/** 205f891b7eSNickeau * 215f891b7eSNickeau * For the canonical meta, see {@link action_plugin_combo_metacanonical} 225f891b7eSNickeau * 235f891b7eSNickeau * Inspiration, reference: 245f891b7eSNickeau * https://developers.facebook.com/docs/sharing/webmasters 255f891b7eSNickeau * https://github.com/twbs/bootstrap/blob/v4-dev/site/layouts/partials/social.html 265f891b7eSNickeau * https://github.com/mprins/dokuwiki-plugin-socialcards/blob/master/action.php 275f891b7eSNickeau */ 285f891b7eSNickeauclass action_plugin_combo_metafacebook extends DokuWiki_Action_Plugin 295f891b7eSNickeau{ 305f891b7eSNickeau 315f891b7eSNickeau const FACEBOOK_APP_ID = "486120022012342"; 325f891b7eSNickeau 335f891b7eSNickeau /** 345f891b7eSNickeau * The image 355f891b7eSNickeau */ 365f891b7eSNickeau const CONF_DEFAULT_FACEBOOK_IMAGE = "defaultFacebookImage"; 375f891b7eSNickeau 385f891b7eSNickeau 395f891b7eSNickeau const CANONICAL = "facebook"; 405f891b7eSNickeau 415f891b7eSNickeau 425f891b7eSNickeau function __construct() 435f891b7eSNickeau { 445f891b7eSNickeau // enable direct access to language strings 455f891b7eSNickeau // ie $this->lang 465f891b7eSNickeau $this->setupLocale(); 475f891b7eSNickeau } 485f891b7eSNickeau 495f891b7eSNickeau public function register(Doku_Event_Handler $controller) 505f891b7eSNickeau { 515f891b7eSNickeau $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'metaFacebookProcessing', array()); 525f891b7eSNickeau } 535f891b7eSNickeau 545f891b7eSNickeau /** 555f891b7eSNickeau * 565f891b7eSNickeau * @param $event 575f891b7eSNickeau */ 585f891b7eSNickeau function metaFacebookProcessing($event) 595f891b7eSNickeau { 605f891b7eSNickeau 615f891b7eSNickeau global $ID; 625f891b7eSNickeau if (empty($ID)) { 635f891b7eSNickeau // $ID is null for media 645f891b7eSNickeau return; 655f891b7eSNickeau } 665f891b7eSNickeau 675f891b7eSNickeau 6885e82846SNickeau $page = Page::createPageFromId($ID); 69f788f694Sgerardnico if (!$page->exists()) { 70dd39a644Sgerardnico return; 71dd39a644Sgerardnico } 7221913ab3SNickeau 735f891b7eSNickeau /** 745f891b7eSNickeau * No social for bars 755f891b7eSNickeau */ 76531e725cSNickeau if ($page->isSlot()) { 775f891b7eSNickeau return; 785f891b7eSNickeau } 795f891b7eSNickeau 805f891b7eSNickeau 815f891b7eSNickeau /** 825f891b7eSNickeau * "og:url" is already created in the {@link action_plugin_combo_metacanonical} 835f891b7eSNickeau * "og:description" is already created in the {@link action_plugin_combo_metadescription} 845f891b7eSNickeau */ 855f891b7eSNickeau $facebookMeta = array( 86c3437056SNickeau "og:title" => StringUtility::truncateString($page->getTitleOrDefault(), 70) 875f891b7eSNickeau ); 88f788f694Sgerardnico $descriptionOrElseDokuWiki = $page->getDescriptionOrElseDokuWiki(); 89f788f694Sgerardnico if (!empty($descriptionOrElseDokuWiki)) { 90f788f694Sgerardnico // happens in test with document without content 91f788f694Sgerardnico $facebookMeta["og:description"] = $descriptionOrElseDokuWiki; 92f788f694Sgerardnico } 935f891b7eSNickeau 945f891b7eSNickeau $title = Site::getTitle(); 955f891b7eSNickeau if (!empty($title)) { 965f891b7eSNickeau $facebookMeta["og:site_name"] = $title; 975f891b7eSNickeau } 985f891b7eSNickeau 995f891b7eSNickeau /** 1005f891b7eSNickeau * Type of page 1015f891b7eSNickeau */ 102c3437056SNickeau $pageType = $page->getTypeOrDefault(); 103c3437056SNickeau switch ($pageType) { 104c3437056SNickeau case PageType::ARTICLE_TYPE: 1055f891b7eSNickeau // https://ogp.me/#type_article 10685e82846SNickeau $facebookMeta["article:published_time"] = $page->getPublishedElseCreationTime()->format(DATE_ISO8601); 107c3437056SNickeau $modifiedTime = $page->getModifiedTimeOrDefault(); 108c3437056SNickeau if ($modifiedTime !== null) { 10985e82846SNickeau $facebookMeta["article:modified_time"] = $modifiedTime->format(DATE_ISO8601); 11085e82846SNickeau } 111c3437056SNickeau $facebookMeta["og:type"] = $pageType; 112c3437056SNickeau break; 113c3437056SNickeau default: 114c3437056SNickeau // The default facebook value 115c3437056SNickeau $facebookMeta["og:type"] = PageType::WEBSITE_TYPE; 116c3437056SNickeau break; 1175f891b7eSNickeau } 1185f891b7eSNickeau 119c3437056SNickeau 1205f891b7eSNickeau /** 1211fa8c418SNickeau * @var Image[] 1225f891b7eSNickeau */ 123c3437056SNickeau $facebookImages = $page->getImagesOrDefaultForTheFollowingUsages([PageImageUsage::FACEBOOK, PageImageUsage::SOCIAL, PageImageUsage::ALL]); 1245f891b7eSNickeau if (empty($facebookImages)) { 1251fa8c418SNickeau $defaultFacebookImage = PluginUtility::getConfValue(self::CONF_DEFAULT_FACEBOOK_IMAGE); 1265f891b7eSNickeau if (!empty($defaultFacebookImage)) { 1271fa8c418SNickeau DokuPath::addRootSeparatorIfNotPresent($defaultFacebookImage); 128c3437056SNickeau $image = Image::createImageFromId($defaultFacebookImage); 1295f891b7eSNickeau if ($image->exists()) { 1305f891b7eSNickeau $facebookImages[] = $image; 1315f891b7eSNickeau } else { 1321fa8c418SNickeau if ($defaultFacebookImage != ":logo-facebook.png") { 1335f891b7eSNickeau LogUtility::msg("The default facebook image ($defaultFacebookImage) does not exist", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1345f891b7eSNickeau } 1355f891b7eSNickeau } 1365f891b7eSNickeau } 1375f891b7eSNickeau } 1385f891b7eSNickeau if (!empty($facebookImages)) { 13921913ab3SNickeau 14021913ab3SNickeau /** 14121913ab3SNickeau * One of image/jpeg, image/gif or image/png 14221913ab3SNickeau * As stated here: https://developers.facebook.com/docs/sharing/webmasters#images 14321913ab3SNickeau **/ 144c3437056SNickeau $facebookMime = [Mime::JPEG, Mime::GIF, Mime::PNG]; 1455f891b7eSNickeau foreach ($facebookImages as $facebookImage) { 1465f891b7eSNickeau 147c3437056SNickeau if (!in_array($facebookImage->getPath()->getMime()->toString(), $facebookMime)) { 14821913ab3SNickeau continue; 14921913ab3SNickeau } 15021913ab3SNickeau 1511fa8c418SNickeau /** @var Image $facebookImage */ 1521fa8c418SNickeau if (!($facebookImage->isRaster())) { 1531fa8c418SNickeau LogUtility::msg("Internal: The image ($facebookImage) is not a raster image and this should not be the case for facebook", LogUtility::LVL_MSG_ERROR); 15421913ab3SNickeau continue; 15521913ab3SNickeau } 15621913ab3SNickeau 1575f891b7eSNickeau if (!$facebookImage->exists()) { 1585f891b7eSNickeau LogUtility::msg("The image ($facebookImage) does not exist and was not added", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1595f891b7eSNickeau } else { 1605f891b7eSNickeau 1615f891b7eSNickeau $toSmall = false; 1625f891b7eSNickeau 1635f891b7eSNickeau // There is a minimum size constraint of 200px by 200px 164*82a60d03SNickeau // The try is in case we can't get the width and height 165*82a60d03SNickeau try { 166*82a60d03SNickeau $intrinsicWidth = $facebookImage->getIntrinsicWidth(); 167*82a60d03SNickeau $intrinsicHeight = $facebookImage->getIntrinsicHeight(); 168*82a60d03SNickeau } catch (ExceptionCombo $e) { 169*82a60d03SNickeau LogUtility::msg("No image was added for facebook. Error while retrieving the dimension of the image: {$e->getMessage()}", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 170*82a60d03SNickeau break; 1715f891b7eSNickeau } 172*82a60d03SNickeau 173*82a60d03SNickeau if ($intrinsicWidth < 200) { 174*82a60d03SNickeau $toSmall = true; 175*82a60d03SNickeau } else { 176*82a60d03SNickeau $facebookMeta["og:image:width"] = $intrinsicWidth; 177*82a60d03SNickeau if ($intrinsicHeight < 200) { 178*82a60d03SNickeau $toSmall = true; 179*82a60d03SNickeau } else { 180*82a60d03SNickeau $facebookMeta["og:image:height"] = $intrinsicHeight; 1815f891b7eSNickeau } 1825f891b7eSNickeau } 1835f891b7eSNickeau 1845f891b7eSNickeau if ($toSmall) { 185*82a60d03SNickeau $message = "The facebook image ($facebookImage) is too small (" . $intrinsicWidth . " x " . $intrinsicHeight . "). The minimum size constraint is 200px by 200px"; 186c3437056SNickeau if ( 187c3437056SNickeau $facebookImage->getPath()->toAbsolutePath()->toString() 188c3437056SNickeau !== 189c3437056SNickeau $page->getFirstImage()->getPath()->toAbsolutePath()->toString() 190c3437056SNickeau ) { 1915f891b7eSNickeau LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1925f891b7eSNickeau } else { 1935f891b7eSNickeau LogUtility::log2BrowserConsole($message); 1945f891b7eSNickeau } 1955f891b7eSNickeau } 1965f891b7eSNickeau 1975f891b7eSNickeau 1985f891b7eSNickeau /** 1995f891b7eSNickeau * We may don't known the dimensions 2005f891b7eSNickeau */ 2015f891b7eSNickeau if (!$toSmall) { 202c3437056SNickeau $mime = $facebookImage->getPath()->getMime()->toString(); 2035f891b7eSNickeau if (!empty($mime)) { 204c3437056SNickeau $facebookMeta["og:image:type"] = $mime; 2055f891b7eSNickeau } 20621913ab3SNickeau $facebookMeta["og:image"] = $facebookImage->getAbsoluteUrl(); 2075f891b7eSNickeau // One image only 2085f891b7eSNickeau break; 2095f891b7eSNickeau } 2105f891b7eSNickeau } 2115f891b7eSNickeau 2125f891b7eSNickeau } 2135f891b7eSNickeau } 2145f891b7eSNickeau 2155f891b7eSNickeau 2165f891b7eSNickeau $facebookMeta["fb:app_id"] = self::FACEBOOK_APP_ID; 2175f891b7eSNickeau 2181fa8c418SNickeau $facebookDefaultLocale = "en_US"; 2191fa8c418SNickeau $locale = $page->getLocale($facebookDefaultLocale); 2201fa8c418SNickeau $facebookMeta["og:locale"] = $locale; 2215f891b7eSNickeau 2225f891b7eSNickeau 2235f891b7eSNickeau /** 2245f891b7eSNickeau * Add the properties 2255f891b7eSNickeau */ 2265f891b7eSNickeau foreach ($facebookMeta as $property => $content) { 2275f891b7eSNickeau $event->data['meta'][] = array("property" => $property, "content" => $content); 2285f891b7eSNickeau } 2295f891b7eSNickeau 2305f891b7eSNickeau 2315f891b7eSNickeau } 2325f891b7eSNickeau 2335f891b7eSNickeau} 234