Changeset 2628020
- Timestamp:
- 11/11/2021 10:28:07 AM (4 years ago)
- Location:
- branded-social-images/trunk
- Files:
-
- 6 edited
-
info.json (modified) (1 diff)
-
lib/class.og-image-plugin.php (modified) (17 diffs)
-
lib/class.og-image.php (modified) (2 diffs)
-
lib/inc.functions.php (modified) (3 diffs)
-
readme.txt (modified) (2 diffs)
-
wp-plugin.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branded-social-images/trunk/info.json
r2626772 r2628020 5 5 "Author": "Internetbureau Clearsite", 6 6 "Author URI": "https://www.clearsite.nl/", 7 "Version": "1.0.1 5",7 "Version": "1.0.16", 8 8 "License": "GPL2" 9 9 } -
branded-social-images/trunk/lib/class.og-image-plugin.php
r2626772 r2628020 173 173 }); 174 174 175 /** 176 * url endpoint, the WordPress way 177 * 178 * pros: 179 * 1. it works on non-standard hosts, 180 * 2. works on nginx hosts 181 * cons: 182 * 1. does not work for custom post-type archives 183 * 2. because it is in essence a page-modifier, WP considers this a page, therefore 184 * - adds a trailing slash 185 * - confusing caching plugins into thinking the content-type should be text/html 186 * 3. the WP construction assumes an /endpoint/value/ set-up, requiring cleanup, see fileter rewrite_rules_array implementation below 187 * 188 * Why this way? 189 * 190 * Because an .htaccess RewriteRule, although improving performance 20-fold, would be web-server-software specific, blog-set-up specific and multi-site aware 191 * which makes it quite impossible to do universally. Unfortunately. 192 * 193 * If you feel adventurous, you can always add it yourself! It should look something like this: 194 * 195 * RewriteRule (.+)/social-image.(jpg|png)/?$ $1/?bsi_img=1 [QSA,L,NC] 196 * 197 * If only for a certain domain, you can add a condition; 198 * 199 * RewriteCond %{HTTP_HOST} yourdomain.com 200 * RewriteRule (.+)/social-image.(jpg|png)/?$ $1/?bsi_img=1 [QSA,L,NC] 201 * 202 * For more information on apache rewrite rules, see 203 * @see https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html 204 */ 205 175 206 add_action('init', function () { 176 207 // does not work in any possible way for Post-Type Archives … … 193 224 }); 194 225 195 add_action('admin_init', function () { 196 $font_file = get_option(self::DEFAULTS_PREFIX . 'text__font'); 197 198 // legacy code follows, todo: investigate removal. 199 if (preg_match('/google:(.+)/', $font_file, $m)) { 200 $defaults = Admin::base_settings(); 201 $this->text_options = $defaults['text_options']; 202 $this->text_options['font-file'] = $font_file; 203 $this->text_options['font-family'] = $font_file; 204 $this->expand_text_options(); 205 if ($this->text_options['font-file'] && is_file($this->text_options['font-file']) && $this->text_options['font-file'] !== $font_file) { // PROCESSED! 206 update_option(self::DEFAULTS_PREFIX . 'text__font', basename($this->text_options['font-file'])); 207 wp_redirect(remove_query_arg('')); 208 exit; 209 } 210 } 211 }); 226 // todo: remove in 1.0.20 release 227 // add_action('admin_init', function () { 228 // $font_file = get_option(self::DEFAULTS_PREFIX . 'text__font'); 229 // 230 // // legacy code follows, todo: investigate removal. 231 // if (preg_match('/google:(.+)/', $font_file, $m)) { 232 // $defaults = Admin::base_settings(); 233 // $this->text_options = $defaults['text_options']; 234 // $this->text_options['font-file'] = $font_file; 235 // $this->text_options['font-family'] = $font_file; 236 // $this->expand_text_options(); 237 // if ($this->text_options['font-file'] && is_file($this->text_options['font-file']) && $this->text_options['font-file'] !== $font_file) { // PROCESSED! 238 // update_option(self::DEFAULTS_PREFIX . 'text__font', basename($this->text_options['font-file'])); 239 // wp_redirect(remove_query_arg('')); 240 // exit; 241 // } 242 // } 243 // }); 212 244 213 245 // this filter is used when a re-save permalink occurs 214 // it changes the rewrite rules so the endpoint is value-less and more a tag, like 'feed' is for WordPress.215 246 add_filter('rewrite_rules_array', function ($rules) { 216 247 $new_rules = []; … … 225 256 } 226 257 $rules = array_merge($pt_archives, $rules); 258 259 /** 260 * changes the rewrite rules so the endpoint is value-less and more a tag, like 'feed' is for WordPress. 261 */ 227 262 foreach ($rules as $source => $target) { 228 263 if ( … … 267 302 add_filter('bsi_post_types', [static::class, 'post_types'], ~PHP_INT_MAX, 0); 268 303 304 /** 305 * Patch the response to WordPress oembed request 306 */ 269 307 add_filter('oembed_response_data', function ($data, $post) { 270 308 $id = $post->ID; … … 281 319 }, PHP_INT_MAX, 2); 282 320 321 /** 322 * Patch SEO by RankMath JD+JSON data 323 */ 283 324 add_filter('rank_math/json_ld', function ($data, $RankMath_schema_jsonld) { 284 325 $id = $RankMath_schema_jsonld->post_id; … … 297 338 } 298 339 340 /** 341 * Test if we want a BSI for this post. 342 * @todo: future version will have to detect archives and categories as well 343 * @param $post_id 344 * @return bool 345 */ 299 346 public static function go_for_id($post_id): bool 300 347 { … … 308 355 } 309 356 357 /** 358 * Logging function used for debugging. 359 * When called with ?debug=BSI, an image url produces debug output 360 * Because some hosts mess with output buffers and/or reverse proxies, this data is not always visible 361 * so it is stored for viewing in the config panel as well. 362 * @return array 363 */ 310 364 public static function log(): array 311 365 { … … 359 413 } 360 414 415 /** 416 * yes, we are mimicking get_plugin_data here because get_plugin_data is not always available while get_file_data is. 417 * we could have statically set the version number, but we could forget to update it. 418 * @return string the version number of the plugin. 419 */ 361 420 public static function get_version() 362 421 { 363 422 static $version; 364 423 if (!$version) { 365 // yes, we are mimicking get_plugin_data here because get_plugin_data is not always available while get_file_data is.366 424 $data = get_file_data(BSI_PLUGIN_FILE, ['Version' => 'Version'], 'plugin'); 367 425 $version = $data['Version']; … … 370 428 } 371 429 430 /** 431 * Retrieves Media-library-item data with a certain size 432 * A mashup of wp_get_attachment_image_src and wp_get_attachment_metadata 433 * @param $image_id 434 * @param string $size 435 * @return array|false 436 */ 372 437 public static function wp_get_attachment_image_data($image_id, string $size) 373 438 { 374 439 $data = wp_get_attachment_image_src($image_id, $size); 375 440 $meta = wp_get_attachment_metadata($image_id); 376 $upl = wp_upload_dir(); 377 $upl = $upl['basedir']; 378 $data[4] = trailingslashit($upl) . $meta['file']; 379 if (!empty($meta['sizes'][$size]['path'])) { 380 $data[4] = trailingslashit($upl) . $meta['sizes'][$size]['path']; 381 } 382 elseif (!empty($meta['sizes'][$size]['file'])) { 383 $file = dirname($data[4]) . '/' . $meta['sizes'][$size]['file']; 441 if (is_array($data) && is_array($meta)) { 442 $upl = wp_upload_dir(); 443 $upl = $upl['basedir']; 444 // path to the base image 445 $file = $base = trailingslashit($upl) . $meta['file']; 446 Plugin::log(sprintf(' Base image for #%d: %s', $image_id, $base)); 447 if (!empty($meta['sizes'][$size]['path'])) { 448 // path to the resized image, if it exists 449 $file = trailingslashit($upl) . $meta['sizes'][$size]['path']; 450 Plugin::log(sprintf(' Using \'path\' entry: %s with size-name %s', $file, $size)); 451 } 452 elseif (!empty($meta['sizes'][$size]['file'])) { 453 // only a new filename is listed, use directory of base. 454 $file = dirname($base) . '/' . $meta['sizes'][$size]['file']; 455 Plugin::log(sprintf(' Using \'file\' entry: %s with size-name %s', $file, $size)); 456 } 457 // check existence of file. 384 458 if (is_file($file)) { 385 459 $data[4] = $file; 460 } 461 else { 462 Plugin::log(' Selected size-specific file does not exist. Please run a thumbnail rebuild.'); 463 if (is_file($base)) { 464 $data[4] = $base; 465 } 466 else { 467 Plugin::log(' Base image also does not exist. THIS IS A PROBLEM!'); 468 } 386 469 } 387 470 } … … 445 528 } 446 529 530 /** 531 * Scrape the title from a rendered page. 532 * This really is an eye-sore and we will replace it with a title-builder in the future. 533 * @param $post_id 534 * @return array|mixed 535 */ 447 536 public static function scrape_title_data($post_id) 448 537 { … … 511 600 $output_format = $output_format[0]; 512 601 } 513 if (!in_array($fallback_format, ['png', 'jpg', 'webp'])) {602 if (!in_array($fallback_format, ['png', 'jpg', /* 'webp' */])) { 514 603 $fallback_format = 'jpg'; 515 604 } … … 524 613 } 525 614 615 /** 616 * wrapper for unlink function for proper error handling or at least error-prevention 617 * @see unlink 618 * 619 * @param $path 620 * @return bool 621 */ 526 622 private static function unlink($path): bool 527 623 { … … 535 631 } 536 632 633 /** 634 * wrapper for rmdir function for proper error handling or at least error-prevention 635 * also clears .DS_Store items (macOS sucks sometimes) before attempting rmdir. 636 * @see rmdir 637 * 638 * @param $path 639 * @return bool 640 */ 537 641 private static function rmdir($path): bool 538 642 { … … 549 653 } 550 654 655 /** 656 * Clear the BSI cache. 657 * @return bool 658 */ 551 659 public static function purge_cache(): bool 552 660 { … … 579 687 } 580 688 689 /** 690 * @param false $destroy_buffer if false; do a nice flush. if true; previous output is destroyed. 691 */ 581 692 public static function no_output_buffers($destroy_buffer = false) 582 693 { … … 639 750 add_filter('wpseo_twitter_image', [static::class, 'overrule_og_image'], PHP_INT_MAX); 640 751 752 // this is a very intrusive way, but Yoast does not allow overruling the 753 // image dimensions. 754 // @todo: investigate the option of always doing it this way. I wanted to prevent it, bus since we cannot 755 // @todo: perhaps we should always just kill all og:image data from the head and add it ourselves. 641 756 add_action('wpseo_head', [static::class, 'patch_wpseo_head'], ~PHP_INT_MAX); 642 757 add_action('wpseo_head', [static::class, 'patch_wpseo_head'], PHP_INT_MAX); … … 2078 2193 } 2079 2194 } 2080 2081 self::track('activate', $network_wide);2082 2195 } 2083 2196 2084 2197 public static function on_deactivation($network_wide) 2085 2198 { 2086 self::track('deactivate', $network_wide); 2199 global $wpdb; 2200 Plugin::purge_cache(); 2201 if ($network_wide && function_exists('is_multisite') && is_multisite()) { 2202 $blog_ids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->base_prefix}blogs"); 2203 foreach ($blog_ids as $blog_id) { 2204 switch_to_blog($blog_id); 2205 Plugin::purge_cache(); 2206 restore_current_blog(); 2207 } 2208 } 2087 2209 } 2088 2210 2089 2211 public static function on_uninstall($network_wide) 2090 2212 { 2091 self::track('uninstall', $network_wide); 2092 } 2093 2094 private static function track($action, $network_wide = false) 2095 { 2096 // tracking disabled for now, we need to find out if this is allowed. 2097 if (defined('BSI_TRACKING_ENABLED')) { 2098 // we like to see where our plugin is used so we can provide support more easily 2099 // note that the only data we collect are plugin name, version and your website URL. 2100 // also note that we do not care about the response. (blocking:false) 2101 wp_remote_get('https://wp.clearsite.nl/tracking/' . ($network_wide ? 'network-' : '') . $action . '/' . 2102 basename(dirname(__DIR__)) . '/' . Plugin::get_version() . '/' . get_bloginfo('url'), 2103 ['blocking' => false] 2104 ); 2105 } 2213 // cannot uninstall without deactivation, so we may expect WordPress to call the dectivation hook. 2214 // no need to do it ourselves. 2106 2215 } 2107 2216 } -
branded-social-images/trunk/lib/class.og-image.php
r2626599 r2628020 311 311 $type = 'none'; 312 312 313 $title = apply_filters('the_title', get_the_title($post_id), $post_id); 314 313 315 if (Plugin::setting('use_bare_post_title')) { 314 316 $type = 'wordpress'; 315 $text = apply_filters('the_title', get_the_title($post_id), $post_id);317 $text = $title; 316 318 Plugin::log('Text consideration: WordPress title (bare); ' . $text); 317 319 } … … 342 344 Plugin::log('Text: No text found, using default; ' . $text); 343 345 $type = 'default'; 346 } 347 if (false !== strpos($text, '{title}')) { 348 Plugin::log('{title} placeholder stored in database. Replacing with actual title.'); 349 Plugin::log(' This is a failsafe, should not happen. Please check the editor javascript console.'); 350 $text = str_replace('{title}', $title, $text); 344 351 } 345 352 -
branded-social-images/trunk/lib/inc.functions.php
r2626772 r2628020 1 1 <?php 2 2 /** 3 * @since 1.0.15 4 * Some hosts do not have the mime_content_type function. 5 * In case it is missing, try alternatives 6 */ 3 7 if (!function_exists('mime_content_type')) { 4 8 function mime_content_type($file) { 9 /** 10 * Alternative 1: finfo 11 * Open a connection to the finfo service and ask for the content-type of the file. 12 */ 5 13 static $f; 6 14 if (function_exists('finfo_open')) { … … 13 21 } 14 22 23 /** 24 * Alternative 2: the WordPress function wp_check_filetype 25 * Why is this not used always, or as an earlier alternative? 26 * Because it falls back on detection by extension, which is far less preferable than mime sniffing 27 * And because it might not exist when we need it. (many parts of WordPress are not available during bootstrap or on front-end) 28 */ 15 29 if (function_exists('wp_check_filetype')) { 16 30 $d = wp_check_filetype($file, []); … … 20 34 } 21 35 22 // if all else fails 23 36 /** 37 * if all else fails; 38 * Alternative 3: mime type based on file extension. 39 * Now this is a potential security risk, but if you are that keen on this; please just fix your webserver to properly 40 * support mime-sniffing on files. 41 * 42 * For our purposes, we only need image/jpeg and image/png, but since this function is missing and we are not alone 43 * in this universe, we need to provide a fairly complete solution. 44 */ 24 45 $mime_types = array( 25 46 'txt' => 'text/plain', -
branded-social-images/trunk/readme.txt
r2626772 r2628020 4 4 Requires at least: 4.7 5 5 Tested up to: 5.8.1 6 Stable tag: 1.0.1 56 Stable tag: 1.0.16 7 7 Requires PHP: 7.0 8 8 License: GPLv2 or later … … 134 134 == Changelog == 135 135 136 = 1.0.16 = 137 * fixed: in some cases, the {title} placeholder gets stored in the post-meta and appears in the generated image. This should not happen as the {title} placeholder is replaced while editing. 138 * cleanup: lot of code cleaned up, comments added 139 * removed: some code suggested support for webp output (instead of png or jpg) but as Facebook and LinkedIn (and probably more) platforms do not support webp for og:image, no reason to try to generate it. 140 136 141 = 1.0.15 = 137 142 * fixed: some users report "function mime_content_type does not exist". This function should exist and indicates a broken/misconfigured server. To accommodate, fallback functions are in place. 138 143 139 144 = 1.0.14 = 145 * warning: Only install this version if your host has the "magic mime" extension properly configured (function mime_content_type exists) 140 146 * important change: Switch from PNG output to JPG output. The reason is disk-space usage; the JPG takes only a fraction of the disk space and has practically the same quality. See the FAQ for more information. 141 147 * fixed: showing debug information leaves image cache in locked state, preventing (re-)generation of image. -
branded-social-images/trunk/wp-plugin.php
r2626772 r2628020 6 6 * Author: Internetbureau Clearsite 7 7 * Author URI: https://clearsite.nl/branded-social-images 8 * Version: 1.0.1 58 * Version: 1.0.16 9 9 * License: GPL2 10 10 */ … … 60 60 }); 61 61 62 register_activation_hook(__FILE__, [Plugin::class, 'on_activation']); 63 register_deactivation_hook(__FILE__, [Plugin::class, 'on_deactivation']); 64 register_uninstall_hook(__FILE__, [Plugin::class, 'on_uninstall']); 62 /** 63 * plugin activation/deactivation/uninstall hooks 64 */ 65 register_activation_hook(BSI_PLUGIN_FILE, [Plugin::class, 'on_activation']); 66 register_deactivation_hook(BSI_PLUGIN_FILE, [Plugin::class, 'on_deactivation']); 67 register_uninstall_hook(BSI_PLUGIN_FILE, [Plugin::class, 'on_uninstall']); 68 65 69 /** 66 70 * Reference list
Note: See TracChangeset
for help on using the changeset viewer.