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