15f891b7eSNickeau<?php 25f891b7eSNickeau 3c3437056SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4c3437056SNickeau 51fa8c418SNickeauuse ComboStrap\DokuPath; 682a60d03SNickeauuse ComboStrap\ExceptionCombo; 71fa8c418SNickeauuse ComboStrap\Image; 85f891b7eSNickeauuse ComboStrap\LogUtility; 9c3437056SNickeauuse ComboStrap\Mime; 105f891b7eSNickeauuse ComboStrap\Page; 11c3437056SNickeauuse ComboStrap\PageImageUsage; 12c3437056SNickeauuse ComboStrap\PageType; 13c3437056SNickeauuse ComboStrap\PluginUtility; 145f891b7eSNickeauuse ComboStrap\Site; 155f891b7eSNickeauuse ComboStrap\StringUtility; 165f891b7eSNickeau 175f891b7eSNickeau 185f891b7eSNickeau/** 195f891b7eSNickeau * 20*4cadd4f8SNickeau * Implementation of the ogp protocol 21*4cadd4f8SNickeau * 22*4cadd4f8SNickeau * followed by: 23*4cadd4f8SNickeau * * Facebook: https://developers.facebook.com/docs/sharing/webmasters 24*4cadd4f8SNickeau * * Linkedin: https://www.linkedin.com/help/linkedin/answer/a521928/making-your-website-shareable-on-linkedin?lang=en 25*4cadd4f8SNickeau * 265f891b7eSNickeau * For the canonical meta, see {@link action_plugin_combo_metacanonical} 275f891b7eSNickeau * 285f891b7eSNickeau * Inspiration, reference: 295f891b7eSNickeau * https://github.com/twbs/bootstrap/blob/v4-dev/site/layouts/partials/social.html 305f891b7eSNickeau * https://github.com/mprins/dokuwiki-plugin-socialcards/blob/master/action.php 31*4cadd4f8SNickeau * 32*4cadd4f8SNickeau * 335f891b7eSNickeau */ 345f891b7eSNickeauclass action_plugin_combo_metafacebook extends DokuWiki_Action_Plugin 355f891b7eSNickeau{ 365f891b7eSNickeau 375f891b7eSNickeau const FACEBOOK_APP_ID = "486120022012342"; 385f891b7eSNickeau 395f891b7eSNickeau /** 405f891b7eSNickeau * The image 415f891b7eSNickeau */ 425f891b7eSNickeau const CONF_DEFAULT_FACEBOOK_IMAGE = "defaultFacebookImage"; 435f891b7eSNickeau 445f891b7eSNickeau 455f891b7eSNickeau const CANONICAL = "facebook"; 465f891b7eSNickeau 475f891b7eSNickeau 485f891b7eSNickeau function __construct() 495f891b7eSNickeau { 505f891b7eSNickeau // enable direct access to language strings 515f891b7eSNickeau // ie $this->lang 525f891b7eSNickeau $this->setupLocale(); 535f891b7eSNickeau } 545f891b7eSNickeau 555f891b7eSNickeau public function register(Doku_Event_Handler $controller) 565f891b7eSNickeau { 575f891b7eSNickeau $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'metaFacebookProcessing', array()); 585f891b7eSNickeau } 595f891b7eSNickeau 605f891b7eSNickeau /** 615f891b7eSNickeau * 625f891b7eSNickeau * @param $event 635f891b7eSNickeau */ 645f891b7eSNickeau function metaFacebookProcessing($event) 655f891b7eSNickeau { 665f891b7eSNickeau 675f891b7eSNickeau global $ID; 685f891b7eSNickeau if (empty($ID)) { 695f891b7eSNickeau // $ID is null for media 705f891b7eSNickeau return; 715f891b7eSNickeau } 725f891b7eSNickeau 735f891b7eSNickeau 7485e82846SNickeau $page = Page::createPageFromId($ID); 75f788f694Sgerardnico if (!$page->exists()) { 76dd39a644Sgerardnico return; 77dd39a644Sgerardnico } 7821913ab3SNickeau 795f891b7eSNickeau /** 805f891b7eSNickeau * No social for bars 815f891b7eSNickeau */ 82*4cadd4f8SNickeau if ($page->isSecondarySlot()) { 835f891b7eSNickeau return; 845f891b7eSNickeau } 855f891b7eSNickeau 865f891b7eSNickeau 875f891b7eSNickeau /** 885f891b7eSNickeau * "og:url" is already created in the {@link action_plugin_combo_metacanonical} 895f891b7eSNickeau * "og:description" is already created in the {@link action_plugin_combo_metadescription} 905f891b7eSNickeau */ 915f891b7eSNickeau $facebookMeta = array( 92c3437056SNickeau "og:title" => StringUtility::truncateString($page->getTitleOrDefault(), 70) 935f891b7eSNickeau ); 94f788f694Sgerardnico $descriptionOrElseDokuWiki = $page->getDescriptionOrElseDokuWiki(); 95f788f694Sgerardnico if (!empty($descriptionOrElseDokuWiki)) { 96f788f694Sgerardnico // happens in test with document without content 97f788f694Sgerardnico $facebookMeta["og:description"] = $descriptionOrElseDokuWiki; 98f788f694Sgerardnico } 995f891b7eSNickeau 1005f891b7eSNickeau $title = Site::getTitle(); 1015f891b7eSNickeau if (!empty($title)) { 1025f891b7eSNickeau $facebookMeta["og:site_name"] = $title; 1035f891b7eSNickeau } 1045f891b7eSNickeau 1055f891b7eSNickeau /** 1065f891b7eSNickeau * Type of page 1075f891b7eSNickeau */ 108c3437056SNickeau $pageType = $page->getTypeOrDefault(); 109c3437056SNickeau switch ($pageType) { 110c3437056SNickeau case PageType::ARTICLE_TYPE: 1115f891b7eSNickeau // https://ogp.me/#type_article 11285e82846SNickeau $facebookMeta["article:published_time"] = $page->getPublishedElseCreationTime()->format(DATE_ISO8601); 113c3437056SNickeau $modifiedTime = $page->getModifiedTimeOrDefault(); 114c3437056SNickeau if ($modifiedTime !== null) { 11585e82846SNickeau $facebookMeta["article:modified_time"] = $modifiedTime->format(DATE_ISO8601); 11685e82846SNickeau } 117c3437056SNickeau $facebookMeta["og:type"] = $pageType; 118c3437056SNickeau break; 119c3437056SNickeau default: 120c3437056SNickeau // The default facebook value 121c3437056SNickeau $facebookMeta["og:type"] = PageType::WEBSITE_TYPE; 122c3437056SNickeau break; 1235f891b7eSNickeau } 1245f891b7eSNickeau 125c3437056SNickeau 1265f891b7eSNickeau /** 1271fa8c418SNickeau * @var Image[] 1285f891b7eSNickeau */ 129c3437056SNickeau $facebookImages = $page->getImagesOrDefaultForTheFollowingUsages([PageImageUsage::FACEBOOK, PageImageUsage::SOCIAL, PageImageUsage::ALL]); 1305f891b7eSNickeau if (empty($facebookImages)) { 1311fa8c418SNickeau $defaultFacebookImage = PluginUtility::getConfValue(self::CONF_DEFAULT_FACEBOOK_IMAGE); 1325f891b7eSNickeau if (!empty($defaultFacebookImage)) { 1331fa8c418SNickeau DokuPath::addRootSeparatorIfNotPresent($defaultFacebookImage); 134c3437056SNickeau $image = Image::createImageFromId($defaultFacebookImage); 1355f891b7eSNickeau if ($image->exists()) { 1365f891b7eSNickeau $facebookImages[] = $image; 1375f891b7eSNickeau } else { 1381fa8c418SNickeau if ($defaultFacebookImage != ":logo-facebook.png") { 1395f891b7eSNickeau LogUtility::msg("The default facebook image ($defaultFacebookImage) does not exist", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1405f891b7eSNickeau } 1415f891b7eSNickeau } 1425f891b7eSNickeau } 1435f891b7eSNickeau } 1445f891b7eSNickeau if (!empty($facebookImages)) { 14521913ab3SNickeau 14621913ab3SNickeau /** 14721913ab3SNickeau * One of image/jpeg, image/gif or image/png 14821913ab3SNickeau * As stated here: https://developers.facebook.com/docs/sharing/webmasters#images 14921913ab3SNickeau **/ 150c3437056SNickeau $facebookMime = [Mime::JPEG, Mime::GIF, Mime::PNG]; 1515f891b7eSNickeau foreach ($facebookImages as $facebookImage) { 1525f891b7eSNickeau 153c3437056SNickeau if (!in_array($facebookImage->getPath()->getMime()->toString(), $facebookMime)) { 15421913ab3SNickeau continue; 15521913ab3SNickeau } 15621913ab3SNickeau 1571fa8c418SNickeau /** @var Image $facebookImage */ 1581fa8c418SNickeau if (!($facebookImage->isRaster())) { 1591fa8c418SNickeau LogUtility::msg("Internal: The image ($facebookImage) is not a raster image and this should not be the case for facebook", LogUtility::LVL_MSG_ERROR); 16021913ab3SNickeau continue; 16121913ab3SNickeau } 16221913ab3SNickeau 1635f891b7eSNickeau if (!$facebookImage->exists()) { 1645f891b7eSNickeau LogUtility::msg("The image ($facebookImage) does not exist and was not added", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1655f891b7eSNickeau } else { 1665f891b7eSNickeau 1675f891b7eSNickeau $toSmall = false; 1685f891b7eSNickeau 1695f891b7eSNickeau // There is a minimum size constraint of 200px by 200px 17082a60d03SNickeau // The try is in case we can't get the width and height 17182a60d03SNickeau try { 17282a60d03SNickeau $intrinsicWidth = $facebookImage->getIntrinsicWidth(); 17382a60d03SNickeau $intrinsicHeight = $facebookImage->getIntrinsicHeight(); 17482a60d03SNickeau } catch (ExceptionCombo $e) { 17582a60d03SNickeau LogUtility::msg("No image was added for facebook. Error while retrieving the dimension of the image: {$e->getMessage()}", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 17682a60d03SNickeau break; 1775f891b7eSNickeau } 17882a60d03SNickeau 17982a60d03SNickeau if ($intrinsicWidth < 200) { 18082a60d03SNickeau $toSmall = true; 18182a60d03SNickeau } else { 18282a60d03SNickeau $facebookMeta["og:image:width"] = $intrinsicWidth; 18382a60d03SNickeau if ($intrinsicHeight < 200) { 18482a60d03SNickeau $toSmall = true; 18582a60d03SNickeau } else { 18682a60d03SNickeau $facebookMeta["og:image:height"] = $intrinsicHeight; 1875f891b7eSNickeau } 1885f891b7eSNickeau } 1895f891b7eSNickeau 1905f891b7eSNickeau if ($toSmall) { 19182a60d03SNickeau $message = "The facebook image ($facebookImage) is too small (" . $intrinsicWidth . " x " . $intrinsicHeight . "). The minimum size constraint is 200px by 200px"; 192c3437056SNickeau if ( 193c3437056SNickeau $facebookImage->getPath()->toAbsolutePath()->toString() 194c3437056SNickeau !== 195c3437056SNickeau $page->getFirstImage()->getPath()->toAbsolutePath()->toString() 196c3437056SNickeau ) { 1975f891b7eSNickeau LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL); 1985f891b7eSNickeau } else { 1995f891b7eSNickeau LogUtility::log2BrowserConsole($message); 2005f891b7eSNickeau } 2015f891b7eSNickeau } 2025f891b7eSNickeau 2035f891b7eSNickeau 2045f891b7eSNickeau /** 2055f891b7eSNickeau * We may don't known the dimensions 2065f891b7eSNickeau */ 2075f891b7eSNickeau if (!$toSmall) { 208c3437056SNickeau $mime = $facebookImage->getPath()->getMime()->toString(); 2095f891b7eSNickeau if (!empty($mime)) { 210c3437056SNickeau $facebookMeta["og:image:type"] = $mime; 2115f891b7eSNickeau } 21221913ab3SNickeau $facebookMeta["og:image"] = $facebookImage->getAbsoluteUrl(); 2135f891b7eSNickeau // One image only 2145f891b7eSNickeau break; 2155f891b7eSNickeau } 2165f891b7eSNickeau } 2175f891b7eSNickeau 2185f891b7eSNickeau } 2195f891b7eSNickeau } 2205f891b7eSNickeau 2215f891b7eSNickeau 2225f891b7eSNickeau $facebookMeta["fb:app_id"] = self::FACEBOOK_APP_ID; 2235f891b7eSNickeau 2241fa8c418SNickeau $facebookDefaultLocale = "en_US"; 2251fa8c418SNickeau $locale = $page->getLocale($facebookDefaultLocale); 2261fa8c418SNickeau $facebookMeta["og:locale"] = $locale; 2275f891b7eSNickeau 2285f891b7eSNickeau 2295f891b7eSNickeau /** 2305f891b7eSNickeau * Add the properties 2315f891b7eSNickeau */ 2325f891b7eSNickeau foreach ($facebookMeta as $property => $content) { 2335f891b7eSNickeau $event->data['meta'][] = array("property" => $property, "content" => $content); 2345f891b7eSNickeau } 2355f891b7eSNickeau 2365f891b7eSNickeau 2375f891b7eSNickeau } 2385f891b7eSNickeau 2395f891b7eSNickeau} 240