xref: /plugin/combo/action/metafacebook.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
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