1<?php 2 3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4 5use ComboStrap\DokuPath; 6use ComboStrap\ExceptionCombo; 7use ComboStrap\Image; 8use ComboStrap\LogUtility; 9use ComboStrap\Mime; 10use ComboStrap\Page; 11use ComboStrap\PageImage; 12use ComboStrap\PageImageUsage; 13use ComboStrap\PageType; 14use ComboStrap\PluginUtility; 15use ComboStrap\Site; 16use ComboStrap\StringUtility; 17 18 19/** 20 * 21 * For the canonical meta, see {@link action_plugin_combo_metacanonical} 22 * 23 * Inspiration, reference: 24 * https://developers.facebook.com/docs/sharing/webmasters 25 * https://github.com/twbs/bootstrap/blob/v4-dev/site/layouts/partials/social.html 26 * https://github.com/mprins/dokuwiki-plugin-socialcards/blob/master/action.php 27 */ 28class action_plugin_combo_metafacebook extends DokuWiki_Action_Plugin 29{ 30 31 const FACEBOOK_APP_ID = "486120022012342"; 32 33 /** 34 * The image 35 */ 36 const CONF_DEFAULT_FACEBOOK_IMAGE = "defaultFacebookImage"; 37 38 39 const CANONICAL = "facebook"; 40 41 42 function __construct() 43 { 44 // enable direct access to language strings 45 // ie $this->lang 46 $this->setupLocale(); 47 } 48 49 public function register(Doku_Event_Handler $controller) 50 { 51 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'metaFacebookProcessing', array()); 52 } 53 54 /** 55 * 56 * @param $event 57 */ 58 function metaFacebookProcessing($event) 59 { 60 61 global $ID; 62 if (empty($ID)) { 63 // $ID is null for media 64 return; 65 } 66 67 68 $page = Page::createPageFromId($ID); 69 if (!$page->exists()) { 70 return; 71 } 72 73 /** 74 * No social for bars 75 */ 76 if ($page->isSlot()) { 77 return; 78 } 79 80 81 /** 82 * "og:url" is already created in the {@link action_plugin_combo_metacanonical} 83 * "og:description" is already created in the {@link action_plugin_combo_metadescription} 84 */ 85 $facebookMeta = array( 86 "og:title" => StringUtility::truncateString($page->getTitleOrDefault(), 70) 87 ); 88 $descriptionOrElseDokuWiki = $page->getDescriptionOrElseDokuWiki(); 89 if (!empty($descriptionOrElseDokuWiki)) { 90 // happens in test with document without content 91 $facebookMeta["og:description"] = $descriptionOrElseDokuWiki; 92 } 93 94 $title = Site::getTitle(); 95 if (!empty($title)) { 96 $facebookMeta["og:site_name"] = $title; 97 } 98 99 /** 100 * Type of page 101 */ 102 $pageType = $page->getTypeOrDefault(); 103 switch ($pageType) { 104 case PageType::ARTICLE_TYPE: 105 // https://ogp.me/#type_article 106 $facebookMeta["article:published_time"] = $page->getPublishedElseCreationTime()->format(DATE_ISO8601); 107 $modifiedTime = $page->getModifiedTimeOrDefault(); 108 if ($modifiedTime !== null) { 109 $facebookMeta["article:modified_time"] = $modifiedTime->format(DATE_ISO8601); 110 } 111 $facebookMeta["og:type"] = $pageType; 112 break; 113 default: 114 // The default facebook value 115 $facebookMeta["og:type"] = PageType::WEBSITE_TYPE; 116 break; 117 } 118 119 120 /** 121 * @var Image[] 122 */ 123 $facebookImages = $page->getImagesOrDefaultForTheFollowingUsages([PageImageUsage::FACEBOOK, PageImageUsage::SOCIAL, PageImageUsage::ALL]); 124 if (empty($facebookImages)) { 125 $defaultFacebookImage = PluginUtility::getConfValue(self::CONF_DEFAULT_FACEBOOK_IMAGE); 126 if (!empty($defaultFacebookImage)) { 127 DokuPath::addRootSeparatorIfNotPresent($defaultFacebookImage); 128 $image = Image::createImageFromId($defaultFacebookImage); 129 if ($image->exists()) { 130 $facebookImages[] = $image; 131 } else { 132 if ($defaultFacebookImage != ":logo-facebook.png") { 133 LogUtility::msg("The default facebook image ($defaultFacebookImage) does not exist", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 134 } 135 } 136 } 137 } 138 if (!empty($facebookImages)) { 139 140 /** 141 * One of image/jpeg, image/gif or image/png 142 * As stated here: https://developers.facebook.com/docs/sharing/webmasters#images 143 **/ 144 $facebookMime = [Mime::JPEG, Mime::GIF, Mime::PNG]; 145 foreach ($facebookImages as $facebookImage) { 146 147 if (!in_array($facebookImage->getPath()->getMime()->toString(), $facebookMime)) { 148 continue; 149 } 150 151 /** @var Image $facebookImage */ 152 if (!($facebookImage->isRaster())) { 153 LogUtility::msg("Internal: The image ($facebookImage) is not a raster image and this should not be the case for facebook", LogUtility::LVL_MSG_ERROR); 154 continue; 155 } 156 157 if (!$facebookImage->exists()) { 158 LogUtility::msg("The image ($facebookImage) does not exist and was not added", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 159 } else { 160 161 $toSmall = false; 162 163 // There is a minimum size constraint of 200px by 200px 164 // The try is in case we can't get the width and height 165 try { 166 $intrinsicWidth = $facebookImage->getIntrinsicWidth(); 167 $intrinsicHeight = $facebookImage->getIntrinsicHeight(); 168 } catch (ExceptionCombo $e) { 169 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 break; 171 } 172 173 if ($intrinsicWidth < 200) { 174 $toSmall = true; 175 } else { 176 $facebookMeta["og:image:width"] = $intrinsicWidth; 177 if ($intrinsicHeight < 200) { 178 $toSmall = true; 179 } else { 180 $facebookMeta["og:image:height"] = $intrinsicHeight; 181 } 182 } 183 184 if ($toSmall) { 185 $message = "The facebook image ($facebookImage) is too small (" . $intrinsicWidth . " x " . $intrinsicHeight . "). The minimum size constraint is 200px by 200px"; 186 if ( 187 $facebookImage->getPath()->toAbsolutePath()->toString() 188 !== 189 $page->getFirstImage()->getPath()->toAbsolutePath()->toString() 190 ) { 191 LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL); 192 } else { 193 LogUtility::log2BrowserConsole($message); 194 } 195 } 196 197 198 /** 199 * We may don't known the dimensions 200 */ 201 if (!$toSmall) { 202 $mime = $facebookImage->getPath()->getMime()->toString(); 203 if (!empty($mime)) { 204 $facebookMeta["og:image:type"] = $mime; 205 } 206 $facebookMeta["og:image"] = $facebookImage->getAbsoluteUrl(); 207 // One image only 208 break; 209 } 210 } 211 212 } 213 } 214 215 216 $facebookMeta["fb:app_id"] = self::FACEBOOK_APP_ID; 217 218 $facebookDefaultLocale = "en_US"; 219 $locale = $page->getLocale($facebookDefaultLocale); 220 $facebookMeta["og:locale"] = $locale; 221 222 223 /** 224 * Add the properties 225 */ 226 foreach ($facebookMeta as $property => $content) { 227 $event->data['meta'][] = array("property" => $property, "content" => $content); 228 } 229 230 231 } 232 233} 234