Changeset 3356282
- Timestamp:
- 09/04/2025 06:23:36 PM (7 months ago)
- Location:
- featured-image-from-url/trunk
- Files:
-
- 2 added
- 1 deleted
- 17 edited
-
admin/api.php (modified) (6 diffs)
-
admin/block.php (modified) (2 diffs)
-
admin/html/cloud.html (modified) (1 diff)
-
admin/html/css/pro.css (modified) (1 diff)
-
admin/html/js/menu-su.js (modified) (1 diff)
-
admin/html/js/meta-box.js (modified) (1 diff)
-
admin/html/menu.html (modified) (2 diffs)
-
admin/html/meta-box.html (modified) (1 diff)
-
admin/html/support-data.html (modified) (1 diff)
-
admin/html/troubleshooting.html (modified) (1 diff)
-
admin/menu.php (modified) (2 diffs)
-
admin/review.php (added)
-
admin/strings.php (modified) (7 diffs)
-
featured-image-from-url.php (modified) (9 diffs)
-
includes/external-post.php (modified) (2 diffs)
-
includes/html/js/json-ld.js (deleted)
-
includes/structured-data.php (added)
-
includes/thumbnail.php (modified) (8 diffs)
-
includes/util.php (modified) (2 diffs)
-
readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
featured-image-from-url/trunk/admin/api.php
r3328447 r3356282 18 18 function fifu_remote_post($endpoint, $array) { 19 19 return fifu_is_local() ? wp_remote_post($endpoint, $array) : wp_safe_remote_post($endpoint, $array); 20 } 21 22 function fifu_api_image_url(WP_REST_Request $request) { 23 $param = $request['post_id'] ?? null; 24 return fifu_main_image_url($param, true); 20 25 } 21 26 … … 652 657 $url = 'https://cdn.fifu.app/' . ($json->bucket_id ?? '') . '/' . ($post->storage_id ?? ''); 653 658 $post->proxy_url = fifu_speedup_get_signed_url($url, 128, 128, $json->bucket_id ?? '', $post->storage_id ?? '', $is_video); 659 660 // sanitize fields 661 $post->storage_id = sanitize_text_field($post->storage_id ?? ''); 662 $post->title = sanitize_text_field($post->title ?? ''); 663 $post->date = sanitize_text_field($post->date ?? ''); 664 $post->meta_key = sanitize_text_field($post->meta_key ?? ''); 665 $post->proxy_url = esc_url_raw($post->proxy_url ?? ''); 666 $post->meta_id = intval($post->meta_id ?? 0); 667 $post->post_id = intval($post->post_id ?? 0); 668 $post->is_category = isset($post->is_category) ? (bool) $post->is_category : false; 654 669 } 655 670 } … … 847 862 $keyword = $request['keyword'] ?? null; 848 863 $urls = fifu_db_get_all_urls($page, $type, $keyword); 864 865 // sanitize output 866 if (is_array($urls)) { 867 foreach ($urls as $u) { 868 if (!is_object($u)) 869 continue; 870 $u->url = esc_url_raw($u->url ?? ''); 871 $u->video_url = isset($u->video_url) && $u->video_url ? esc_url_raw($u->video_url) : null; 872 $u->post_title = sanitize_text_field($u->post_title ?? ''); 873 $u->post_name = sanitize_text_field($u->post_name ?? ''); 874 $u->post_date = sanitize_text_field($u->post_date ?? ''); 875 $u->meta_key = sanitize_text_field($u->meta_key ?? ''); 876 $u->meta_id = intval($u->meta_id ?? 0); 877 $u->post_id = intval($u->post_id ?? 0); 878 // ensure boolean-ish as int (0/1) 879 $u->category = isset($u->category) ? (int) (!!$u->category) : 0; 880 } 881 } 882 849 883 return $urls; 850 884 } … … 857 891 $type = $request['type'] ?? null; 858 892 $keyword = $request['keyword'] ?? null; 859 return fifu_db_get_posts_with_internal_featured_image($page, $type, $keyword); 893 $results = fifu_db_get_posts_with_internal_featured_image($page, $type, $keyword); 894 895 // sanitize output 896 if (is_array($results)) { 897 foreach ($results as $r) { 898 if (!is_object($r)) 899 continue; 900 $r->url = esc_url_raw($r->url ?? ''); 901 $r->post_title = sanitize_text_field($r->post_title ?? ''); 902 $r->post_name = sanitize_text_field($r->post_name ?? ''); 903 $r->post_date = sanitize_text_field($r->post_date ?? ''); 904 $r->gallery_ids = isset($r->gallery_ids) ? sanitize_text_field($r->gallery_ids) : null; 905 $r->post_id = intval($r->post_id ?? 0); 906 $r->thumbnail_id = intval($r->thumbnail_id ?? 0); 907 $r->category = isset($r->category) ? (int) (!!$r->category) : 0; 908 } 909 } 910 911 return $results; 860 912 } 861 913 … … 1195 1247 )); 1196 1248 1249 register_rest_route('featured-image-from-url/v1', '/url/(?P<post_id>\d+)', array( 1250 'methods' => 'GET', 1251 'callback' => 'fifu_api_image_url', 1252 'permission_callback' => 'fifu_get_private_data_permissions_check', 1253 )); 1254 1197 1255 register_rest_route('featured-image-from-url/v2', '/create_thumbnails_list/', array( 1198 1256 'methods' => 'POST', … … 1277 1335 return true; 1278 1336 } 1337 -
featured-image-from-url/trunk/admin/block.php
r3352132 r3356282 4 4 // Prevent block registration in Customizer 5 5 if (is_admin() && isset($GLOBALS['wp_customize']) && $GLOBALS['wp_customize'] instanceof WP_Customize_Manager) { 6 return; 7 } 8 9 // Prevent block registration on the widgets screen 10 if (is_admin() && basename($_SERVER['PHP_SELF']) === 'widgets.php') { 6 11 return; 7 12 } … … 66 71 67 72 add_action('init', 'fifu_register_meta'); 73 -
featured-image-from-url/trunk/admin/html/cloud.html
r3348282 r3356282 608 608 </div> 609 609 </div> 610 611 <script>612 jQuery(document).ready(function () {613 removeNotices();614 });615 616 // remove notices from other plugins617 setTimeout(function () {618 removeNotices();619 }, 250);620 621 function removeNotices() {622 jQuery('div.header-box > div').remove();623 jQuery('.notice').remove();624 jQuery('[id^=wp-admin-bar-_]').remove();625 jQuery('.pms-cross-promo').remove();626 }627 </script> -
featured-image-from-url/trunk/admin/html/css/pro.css
r3111474 r3356282 4 4 5 5 span.fifu-pro-icon { 6 font-size:32px; 7 color: #d63638; 8 filter: drop-shadow(5px 5px 5px #888888); 6 font-size: 32px; 7 filter: drop-shadow(1px 1px 1px #888888); 9 8 position: relative; 10 9 left: -25px; 11 top: - 7px;10 top: -1px; 12 11 } 12 13 /* Replace the lock/crown with a compact PRO badge */ 14 .dashicons-lock.fifu-pro-icon:before { 15 content: 'PRO' !important; 16 display: inline-block; 17 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Helvetica Neue", Arial, sans-serif !important; 18 font-weight: 700; 19 font-size: 11px; 20 letter-spacing: 0.5px; 21 color: #111111; 22 background: #d4af37; /* gold */ 23 padding: 2px 6px; 24 border-radius: 1px; 25 line-height: 1.2; 26 } -
featured-image-from-url/trunk/admin/html/js/menu-su.js
r3352132 r3356282 729 729 }, 730 730 async: true, 731 beforeSend: function (xhr) { 732 xhr.setRequestHeader('X-WP-Nonce', fifuScriptVars.nonce); 733 }, 734 success: function (data) { 731 // Ensure we expect JSON and gracefully handle empty responses 732 dataType: 'json', 733 dataFilter: function (raw, type) { 734 if (type === 'json') { 735 if (!raw || (typeof raw === 'string' && raw.trim() === '')) 736 return '[]'; 737 } 738 return raw; 739 }, 740 beforeSend: function (xhr) { 741 xhr.setRequestHeader('X-WP-Nonce', fifuScriptVars.nonce); 742 }, 743 success: function (data) { 744 // Normalize unexpected values to an empty array 745 if (!Array.isArray(data)) 746 data = []; 747 735 748 for (var i = 0; i < data.length; i++) { 736 749 imgTag = '<img loading="lazy" id="' + data[i]['meta_id'] + '" src="' + data[i]['url'] + '" style="border-radius:5%; height:56px; width:56px; object-fit:cover; text-align:center">'; -
featured-image-from-url/trunk/admin/html/js/meta-box.js
r3348282 r3356282 728 728 }); 729 729 })(jQuery); 730 731 // Auto-refresh FIFU fields after successful post save (Gutenberg) 732 (function () { 733 try { 734 if (typeof wp === 'undefined' || !wp.data || !wp.data.select || !wp.data.subscribe) 735 return; 736 737 let wasSaving = false; 738 739 function fetchAndApplyFifuUrl(postId) { 740 if (!postId) 741 return; 742 743 // Use the plugin REST endpoint that returns the current main URL 744 const base = ((typeof restUrl !== 'undefined' && restUrl) || (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/'); 745 const url = (base.endsWith('/') ? base : base + '/') + 'featured-image-from-url/v1/url/' + postId + '?_ts=' + Date.now(); 746 fetch(url, { 747 method: 'GET', 748 headers: { 749 'X-WP-Nonce': (window.wpApiSettings && window.wpApiSettings.nonce) || (typeof fifuScriptVars !== 'undefined' ? fifuScriptVars.nonce : '') 750 }, 751 credentials: 'same-origin' 752 }).then(function (res) { 753 // Only proceed on 2xx 754 if (!res || !res.ok) 755 return null; 756 // Endpoint returns a JSON-encoded string (the URL) 757 if (res.headers.get('content-type') && res.headers.get('content-type').indexOf('application/json') !== -1) 758 return res.json(); 759 return res.text(); 760 }).then(function (value) { 761 if (value == null) 762 return; 763 var newUrl = ''; 764 if (typeof value === 'string') { 765 newUrl = value; 766 } else if (value && typeof value === 'object') { 767 // In case the server wraps it differently in some environments 768 newUrl = value.url || ''; 769 } 770 771 if (!newUrl) 772 return; 773 774 // Only update if different from current input 775 var $input = jQuery('#fifu_input_url'); 776 if (!$input.length) 777 return; 778 779 const current = ($input.val() || '').trim(); 780 if (current === newUrl) 781 return; 782 783 $input.val(newUrl) 784 .trigger('input') 785 .trigger('change'); 786 // Recompute preview and controls 787 if (typeof fifu_get_sizes === 'function') 788 fifu_get_sizes(); 789 }).catch(function () { 790 // Ignore network/rest errors silently 791 }); 792 } 793 794 wp.data.subscribe(function () { 795 try { 796 const sel = wp.data.select('core/editor'); 797 // Some WP versions may not expose didPostSaveRequestSucceed 798 if (!sel || !sel.isSavingPost) 799 return; 800 801 const isSaving = !!sel.isSavingPost(); 802 const isAutosaving = !!(sel.isAutosavingPost && sel.isAutosavingPost()); 803 const didSucceed = sel.didPostSaveRequestSucceed ? !!sel.didPostSaveRequestSucceed() : true; 804 805 // Detect transition: saving -> not saving, success, and not autosave 806 if (wasSaving && !isSaving && didSucceed && !isAutosaving) { 807 const postId = (sel.getCurrentPostId && sel.getCurrentPostId()) || (fifuMetaBoxVars && fifuMetaBoxVars.get_the_ID) || null; 808 fetchAndApplyFifuUrl(postId); 809 } 810 811 wasSaving = isSaving; 812 } catch (e) { 813 // no-op 814 } 815 }); 816 } catch (e) { 817 // Guard for non-Gutenberg screens 818 } 819 })(); -
featured-image-from-url/trunk/admin/html/menu.html
r3352132 r3356282 5726 5726 <div style="font-style:italic;font-size:13px;color:white;padding-left:40px"><?php $fifu['start']['post']['new']() ?></div> 5727 5727 <br> 5728 <div style="font-style:italic;font-size:13px;color:white;padding-left:40px"><?php $fifu['start']['post']['box']() ?> <span class="dashicons dashicons-camera" style="font-size:18px;padding-right:3px"></span><b><?php $fifu['start']['post']['featured']() ?></b> ;</div>5728 <div style="font-style:italic;font-size:13px;color:white;padding-left:40px"><?php $fifu['start']['post']['box']() ?> <span class="dashicons dashicons-camera" style="font-size:18px;padding-right:3px"></span><b><?php $fifu['start']['post']['featured']() ?></b></div> 5729 5729 <br> 5730 5730 <div style="font-style:italic;font-size:13px;color:white;padding-left:40px"><?php $fifu['start']['post']['address']() ?></div> … … 5828 5828 </div> 5829 5829 </div> 5830 5831 <script>5832 jQuery(document).ready(function () {5833 removeNotices();5834 });5835 5836 // remove notices from other plugins5837 setTimeout(function () {5838 removeNotices();5839 }, 250);5840 5841 function removeNotices() {5842 jQuery('div.header-box > div').remove();5843 jQuery('.notice').remove();5844 jQuery('[id^=wp-admin-bar-_]').remove();5845 jQuery('.pms-cross-promo').remove();5846 }5847 </script> -
featured-image-from-url/trunk/admin/html/meta-box.html
r3348282 r3356282 39 39 name="fifu_input_url" 40 40 placeholder="<?php $fifu['image']['keywords']() ?>" 41 value="<?php echo esc_ url($url ?? ''); ?>"41 value="<?php echo esc_attr($url ?? ''); ?>" 42 42 style="<?php echo $width ?>;font-size:13px;" /> 43 43 </td> -
featured-image-from-url/trunk/admin/html/support-data.html
r3344902 r3356282 63 63 64 64 <script> 65 jQuery(document).ready(function () {66 removeNotices();67 });68 69 // remove notices from other plugins70 setTimeout(function () {71 removeNotices();72 }, 250);73 74 function removeNotices() {75 jQuery('div.header-box > div').remove();76 jQuery('.notice').remove();77 jQuery('[id^=wp-admin-bar-_]').remove();78 jQuery('.pms-cross-promo').remove();79 }80 81 65 jQuery('#fifu-clipboard').on('click', function() { 82 66 jQuery("#bar").select(); -
featured-image-from-url/trunk/admin/html/troubleshooting.html
r3341179 r3356282 1512 1512 </div> 1513 1513 </div> 1514 1515 <script>1516 jQuery(document).ready(function () {1517 removeNotices();1518 });1519 1520 // remove notices from other plugins1521 setTimeout(function () {1522 removeNotices();1523 }, 250);1524 1525 function removeNotices() {1526 jQuery('div.header-box > div').remove();1527 jQuery('.notice').remove();1528 jQuery('[id^=wp-admin-bar-_]').remove();1529 jQuery('.pms-cross-promo').remove();1530 }1531 </script> -
featured-image-from-url/trunk/admin/menu.php
r3348282 r3356282 13 13 14 14 if (isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], FIFU_SLUG) !== false || strpos($_SERVER['REQUEST_URI'], 'fifu') !== false)) { 15 wp_enqueue_script('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/ 6.1.1/js/all.min.js');15 wp_enqueue_script('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/js/all.min.js'); 16 16 wp_enqueue_style('jquery-ui-style1', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css'); 17 17 wp_enqueue_style('jquery-ui-style2', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.structure.min.css'); 18 18 wp_enqueue_style('jquery-ui-style3', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.theme.min.css'); 19 19 20 wp_enqueue_style('fifu-pro-css', plugins_url('/html/css/pro.css', __FILE__), array(), fifu_version_number_enq()); 20 $pro_css_path = plugin_dir_path(__FILE__) . '/html/css/pro.css'; 21 $pro_css_ver = file_exists($pro_css_path) ? filemtime($pro_css_path) : fifu_version_number_enq(); 22 wp_enqueue_style('fifu-pro-css', plugins_url('/html/css/pro.css', __FILE__), array(), $pro_css_ver); 21 23 22 24 wp_enqueue_script('jquery-ui', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js'); … … 45 47 add_submenu_page(FIFU_SLUG, 'FIFU Troubleshooting', $fifu['options']['troubleshooting'](), 'manage_options', 'fifu-troubleshooting', 'fifu_troubleshooting'); 46 48 add_submenu_page(FIFU_SLUG, 'FIFU Status', $fifu['options']['status'](), 'manage_options', 'fifu-support-data', 'fifu_support_data'); 47 add_submenu_page(FIFU_SLUG, 'FIFU Pro', '<a href="https://fifu.app/" target="_blank"><div style="padding:5px;color:white;background-color:#1da867">' . $fifu['options']['upgrade']() . '</div></a>', 'manage_options', '#', null); 49 add_submenu_page( 50 FIFU_SLUG, 51 'FIFU Pro', 52 '<a href="https://fifu.app/" target="_blank"><div style="padding:5px;color:#111;background-color:#d4af37">' . $fifu['options']['upgrade']() . '</div></a>', 53 'manage_options', 54 '#', 55 null 56 ); 48 57 49 58 add_action('admin_init', 'fifu_get_menu_settings'); -
featured-image-from-url/trunk/admin/strings.php
r3352132 r3356282 330 330 _e("Auto set featured image from Unsplash using tags", FIFU_SLUG); 331 331 }; 332 $fifu['title']['share'] = function () { 333 _e("Auto-share to social media", FIFU_SLUG); 334 }; 332 335 $fifu['title']['block'] = function () { 333 336 _e("Disable right-click", FIFU_SLUG); … … 1634 1637 // pro 1635 1638 $fifu['unlock'] = function () { 1636 _e("U nlock all PRO features for €29.90", FIFU_SLUG);1639 _e("Upgrade to PRO", FIFU_SLUG); 1637 1640 }; 1638 1641 … … 2009 2012 // pro 2010 2013 $fifu['unlock'] = function () { 2011 return __("U nlock all PRO features for €29.90", FIFU_SLUG);2014 return __("Upgrade to PRO", FIFU_SLUG); 2012 2015 }; 2013 2016 … … 2047 2050 }; 2048 2051 $fifu['unsplash']['unlock'] = function () { 2049 return __("U nlock all PRO features for €29.90", FIFU_SLUG);2052 return __("Upgrade to PRO", FIFU_SLUG); 2050 2053 }; 2051 2054 $fifu['unsplash']['more'] = function () { … … 2334 2337 // pro 2335 2338 $fifu['unlock'] = function () { 2336 _e("U nlock all PRO features for €29.90", FIFU_SLUG);2339 _e("Upgrade to PRO", FIFU_SLUG); 2337 2340 }; 2338 2341 … … 2491 2494 }; 2492 2495 $fifu['upgrade'] = function () { 2493 return __("Upgrade to <b>PRO</b> for €29.90", FIFU_SLUG);2496 return __("Upgrade to <b>PRO</b>", FIFU_SLUG); 2494 2497 }; 2495 2498 $fifu['star'] = function () { … … 2498 2501 $fifu['settings'] = function () { 2499 2502 return __("Settings", FIFU_SLUG); 2503 }; 2504 2505 // Plugins screen and review notice 2506 $fifu['rate'] = function () { 2507 return __("Rate ★★★★★", FIFU_SLUG); 2508 }; 2509 $fifu['review']['title'] = function () { 2510 return __("Enjoying FIFU?", FIFU_SLUG); 2511 }; 2512 $fifu['review']['message'] = function () { 2513 return __("If the Featured Image from URL plugin helps you, please consider leaving a 5-star review. It means a lot!", FIFU_SLUG); 2514 }; 2515 $fifu['review']['leave'] = function () { 2516 return __("Leave a review", FIFU_SLUG); 2517 }; 2518 $fifu['review']['later'] = function () { 2519 return __("Not now", FIFU_SLUG); 2520 }; 2521 $fifu['review']['done'] = function () { 2522 return __("I already did", FIFU_SLUG); 2523 }; 2524 $fifu['review']['help'] = function () { 2525 return __("Need help?", FIFU_SLUG); 2500 2526 }; 2501 2527 -
featured-image-from-url/trunk/featured-image-from-url.php
r3352132 r3356282 5 5 * Plugin URI: https://fifu.app/ 6 6 * Description: Use remote media as the featured image and beyond. 7 * Version: 5.2. 67 * Version: 5.2.7 8 8 * Author: fifu.app 9 9 * Author URI: https://fifu.app/ … … 28 28 // Required includes with error handling 29 29 $required_includes = [ 30 FIFU_INCLUDES_DIR . '/util.php', 31 FIFU_INCLUDES_DIR . '/structured-data.php', 30 32 FIFU_INCLUDES_DIR . '/attachment.php', 31 33 FIFU_INCLUDES_DIR . '/convert-url.php', … … 35 37 FIFU_INCLUDES_DIR . '/thumbnail.php', 36 38 FIFU_INCLUDES_DIR . '/thumbnail-category.php', 37 FIFU_INCLUDES_DIR . '/util.php',38 39 FIFU_INCLUDES_DIR . '/woo.php' 39 40 ]; … … 60 61 FIFU_ADMIN_DIR . '/rsa.php', 61 62 FIFU_ADMIN_DIR . '/strings.php', 63 FIFU_ADMIN_DIR . '/review.php', 62 64 FIFU_ADMIN_DIR . '/sheet-editor.php', 63 65 FIFU_ADMIN_DIR . '/transient.php', … … 97 99 fifu_activate_actions(); 98 100 fifu_set_author(); 101 // record installed time per site for review timing 102 if (!get_option('fifu_installed_time')) 103 update_option('fifu_installed_time', time()); 99 104 restore_current_blog(); 100 105 } … … 107 112 // Set redirect transient only for non-multisite 108 113 set_transient('fifu_redirect_to_settings', true, 30); 114 // record installed time for review timing 115 if (!get_option('fifu_installed_time')) 116 update_option('fifu_installed_time', time()); 109 117 } 110 118 } … … 170 178 $strings = fifu_get_strings_plugins(); 171 179 $links[] = '<a href="' . esc_url(get_admin_url(null, 'admin.php?page=featured-image-from-url')) . '">' . $strings['settings']() . '</a>'; 180 $links[] = '<a href="https://fifu.app/" target="_blank" rel="noopener noreferrer">' . $strings['upgrade']() . '</a>'; 172 181 return $links; 173 182 } … … 177 186 function fifu_row_meta($plugin_meta, $plugin_file, $plugin_data, $status) { 178 187 if (strpos($plugin_file, 'featured-image-from-url.php') !== false) { 188 $strings = fifu_get_strings_plugins(); 179 189 $email = '<a style="color:#2271b1">[email protected]</a>'; 180 190 $new_links = array( 181 191 'email' => $email, 192 'rate' => '<a href="https://wordpress.org/support/plugin/featured-image-from-url/reviews/?filter=5#new-post" target="_blank" rel="noopener noreferrer">' . $strings['rate']() . '</a>', 182 193 ); 183 194 $plugin_meta = array_merge($plugin_meta, $new_links); … … 224 235 } 225 236 }); 237 -
featured-image-from-url/trunk/includes/external-post.php
r3328447 r3356282 49 49 50 50 $src = fifu_get_attribute('src', $tag); 51 if (!preg_match('/^https?:\/\//', $src)) 51 // resolve to absolute URL (supports relative and protocol-relative) 52 $abs = fifu_resolve_absolute_url($post_id, $src); 53 if (!$abs) 52 54 continue; 53 55 … … 74 76 // src 75 77 $src = fifu_get_attribute('src', $tag); 76 77 if (! preg_match('/^https?:\/\//', $src))78 $abs = fifu_resolve_absolute_url($post_id, $src); 79 if (!$abs) 78 80 return null; 79 81 80 return $src; 82 return $abs; 83 } 84 85 // Resolve relative or protocol-relative URLs to absolute using the post permalink as base 86 function fifu_resolve_absolute_url($post_id, $url) { 87 $url = trim((string) $url); 88 if ($url === '') 89 return null; 90 91 // ignore data URIs 92 if (stripos($url, 'data:') === 0) 93 return null; 94 95 // already absolute 96 if (preg_match('/^https?:\/\//i', $url)) 97 return $url; 98 99 // looks like a domain without scheme (e.g., youtu.be/abc, www.example.com/a) 100 if (preg_match('/^(?:www\.)?[a-z0-9.-]+\.[a-z]{2,}(?::\d+)?(?:\/.+)?$/i', $url)) { 101 $scheme = is_ssl() ? 'https' : 'http'; 102 return $scheme . '://' . ltrim($url, '/'); 103 } 104 105 // protocol-relative (e.g., //example.com/img.jpg) 106 if (strpos($url, '//') === 0) { 107 $scheme = is_ssl() ? 'https:' : 'http:'; 108 return $scheme . $url; 109 } 110 111 // base for resolution: post permalink or site home 112 $base = get_permalink($post_id); 113 if (!$base) 114 $base = home_url('/'); 115 116 $base_parts = wp_parse_url($base); 117 if (!$base_parts || empty($base_parts['host'])) 118 return null; 119 120 $scheme = $base_parts['scheme'] ?? (is_ssl() ? 'https' : 'http'); 121 $host = $base_parts['host']; 122 $port = isset($base_parts['port']) ? ':' . $base_parts['port'] : ''; 123 $base_path = $base_parts['path'] ?? '/'; 124 125 // same-host absolute-path reference 126 if (isset($url[0]) && $url[0] === '/') { 127 $path = $url; 128 $path = fifu_remove_dot_segments($path); 129 return $scheme . '://' . $host . $port . $path; 130 } 131 132 // query-only or fragment-only reference 133 if (isset($url[0]) && ($url[0] === '?' || $url[0] === '#')) { 134 return $scheme . '://' . $host . $port . $base_path . $url; 135 } 136 137 // relative path reference 138 $dir = (substr($base_path, -1) === '/') ? rtrim($base_path, '/') : rtrim(dirname($base_path), '/'); 139 if ($dir === '/' || $dir === '\\') 140 $dir = ''; 141 $path = ($dir ? $dir : '') . '/' . $url; 142 $path = fifu_remove_dot_segments($path); 143 144 return $scheme . '://' . $host . $port . $path; 145 } 146 147 function fifu_remove_dot_segments($path) { 148 $leading_slash = (strlen($path) > 0 && $path[0] === '/'); 149 $segments = explode('/', $path); 150 $output = []; 151 foreach ($segments as $seg) { 152 if ($seg === '' || $seg === '.') { 153 continue; 154 } 155 if ($seg === '..') { 156 array_pop($output); 157 continue; 158 } 159 $output[] = $seg; 160 } 161 $normalized = ($leading_slash ? '/' : '') . implode('/', $output); 162 // preserve trailing slash if original had it and not query/fragment 163 if ($normalized !== '/' && substr($path, -1) === '/') 164 $normalized .= '/'; 165 return $normalized === '' ? '/' : $normalized; 81 166 } 82 167 -
featured-image-from-url/trunk/includes/thumbnail.php
r3352132 r3356282 4 4 5 5 add_filter('wp_head', 'fifu_add_js'); 6 7 if (!function_exists('is_plugin_active'))8 require_once(ABSPATH . '/wp-admin/includes/plugin.php');9 6 10 7 global $pagenow; 11 8 if (!isset($pagenow) || !in_array($pagenow, array('post.php', 'post-new.php', 'admin-ajax.php', 'wp-cron.php'))) { 12 if ( is_plugin_active('wordpress-seo/wp-seo.php')) {9 if (fifu_is_yoast_seo_active()) { 13 10 add_action('wpseo_opengraph_image', 'fifu_add_social_tag_yoast'); 14 11 add_action('wpseo_twitter_image', 'fifu_add_social_tag_yoast'); … … 16 13 } else 17 14 add_filter('wp_head', 'fifu_add_social_tags'); 15 16 // Always handle FIFU structured data (image-only when SEO plugin is active) 17 add_action('wp_head', 'fifu_add_structured_data', 99); 18 18 } 19 19 … … 77 77 } 78 78 79 // General ld+json output: when an SEO plugin is active we emit only ImageObject 80 // Otherwise we emit minimal BlogPosting/Product with images 81 function fifu_add_structured_data() { 82 // Keep behavior consistent with other meta handling 83 if (is_front_page() || is_home() || is_tax()) 84 return; 85 86 $post_id = get_the_ID(); 87 if (!$post_id) 88 return; 89 90 global $wpdb; 91 $arr = $wpdb->get_col($wpdb->prepare( 92 "SELECT meta_value FROM $wpdb->postmeta WHERE post_id = %d AND meta_key LIKE %s", 93 $post_id, 94 'fifu_%image_url%' 95 )); 96 97 if (empty($arr)) 98 return; 99 100 $type = get_post_type($post_id); 101 if (!empty($arr) && is_singular($type)) 102 fifu_render_structured_data($post_id, $arr); 103 } 104 79 105 function fifu_add_social_tags() { 80 106 if (is_front_page() || is_home() || is_tax()) … … 90 116 $title = str_replace("'", "'", strip_tags(get_the_title($post_id))); 91 117 $description = str_replace("'", "'", wp_strip_all_tags(get_post_field('post_excerpt', $post_id))); 92 93 $arr = array($url);94 95 // https://search.google.com/test/rich-results96 // Add JSON-LD for WordPress posts and products97 $type = get_post_type($post_id);98 if (is_singular($type)) {99 wp_enqueue_script('fifu-json-ld', plugins_url('/html/js/json-ld.js', __FILE__), array(), fifu_version_number_enq());100 $json_ld = [101 "@context" => "https://schema.org",102 "url" => get_permalink($post_id),103 "image" => $arr,104 ];105 if ($type === 'product') {106 $json_ld["@type"] = "Product";107 $json_ld["name"] = get_the_title($post_id);108 } else {109 $json_ld["@type"] = "BlogPosting";110 $json_ld["headline"] = get_the_title($post_id);111 }112 wp_localize_script('fifu-json-ld', 'fifuJsonLd', $json_ld);113 }114 118 115 119 if ($url) { … … 216 220 $alt = get_post_meta($post_id, 'fifu_image_alt', true); 217 221 if (!$alt) { 218 $alt = strip_tags(get_the_title($post_id));219 $title = $title ? $title : $alt;222 $alt = esc_attr(strip_tags(get_the_title($post_id))); 223 $title = esc_attr($title ? $title : $alt); 220 224 $custom_alt = 'alt=' . $delimiter . $alt . $delimiter . ' title=' . $delimiter . $title . $delimiter; 221 225 $html = preg_replace('/alt=[\'\"][^[\'\"]*[\'\"]/', $custom_alt, $html); … … 223 227 } else { 224 228 $alt = strip_tags($alt); 225 $title = $title ? $title : $alt;229 $title = esc_attr($title ? $title : $alt); 226 230 if ($url && $alt) { 227 231 $html = preg_replace('/alt=[\'\"][^[\'\"]*[\'\"]/', 'alt=' . $delimiter . $alt . $delimiter . ' title=' . $delimiter . $title . $delimiter, $html); … … 262 266 } 263 267 264 return sprintf('<img src="%s" alt="%s" title="%s" style="%s" data-large_image="%s" data-large_image_width="%s" data-large_image_height="%s" onerror="%s" width="%s" height="%s">', $url, $alt, $alt, $css, $url, "800", "600", "jQuery(this).hide();", $width, $height); 268 $safe_url = esc_url($url); 269 $safe_alt = esc_attr($alt); 270 $safe_css = esc_attr($css); 271 $safe_width = esc_attr($width); 272 $safe_height = esc_attr($height); 273 274 return sprintf( 275 '<img src="%s" alt="%s" title="%s" style="%s" data-large_image="%s" data-large_image_width="%s" data-large_image_height="%s" onerror="%s" width="%s" height="%s">', 276 $safe_url, 277 $safe_alt, 278 $safe_alt, 279 $safe_css, 280 $safe_url, 281 "800", 282 "600", 283 "jQuery(this).hide();", 284 $safe_width, 285 $safe_height 286 ); 265 287 } 266 288 … … 291 313 foreach ($matches[1] as $match) { 292 314 $content_img_url = html_entity_decode($match); 293 if ($content_img_url == $att_url) { 315 // Simple: exact or content URL is a substring of the attachment URL 316 $should_replace = ($content_img_url == $att_url) || ($content_img_url !== '' && strpos($att_url, $content_img_url) !== false); 317 if ($should_replace) { 294 318 $content = preg_replace('/<img[^>]+src=[\'"]' . preg_quote($match, '/') . '[\'"][^>]*>/i', '', $content, 1); 295 319 return $content; -
featured-image-from-url/trunk/includes/util.php
r3344902 r3356282 1 1 <?php 2 3 // Ensure WordPress plugin functions are available for helper checks 4 require_once(ABSPATH . '/wp-admin/includes/plugin.php'); 2 5 3 6 function fifu_get_attribute($attribute, $html) { … … 327 330 } 328 331 332 // SEO plugins helpers used across the plugin 333 function fifu_is_yoast_seo_active() { 334 return is_plugin_active('wordpress-seo/wp-seo.php'); 335 } 336 337 function fifu_is_aioseo_active() { 338 // Support free and pro identifiers 339 return is_plugin_active('all-in-one-seo-pack/all_in_one_seo_pack.php') || 340 is_plugin_active('all-in-one-seo-pack-pro/all_in_one_seo_pack.php'); 341 } 342 343 function fifu_is_any_seo_plugin_active() { 344 return fifu_is_yoast_seo_active() || fifu_is_rank_math_seo_active() || fifu_is_aioseo_active(); 345 } 346 329 347 function fifu_is_gravity_forms_active() { 330 348 return is_plugin_active('gravityforms/gravityforms.php'); -
featured-image-from-url/trunk/readme.txt
r3352132 r3356282 5 5 Requires at least: 5.6 6 6 Tested up to: 6.8.2 7 Stable tag: 5.2. 67 Stable tag: 5.2.7 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html 10 10 11 Use a remote image/video/audio as featured image of a post or WooCommerce product.11 Use remote media as the featured image and beyond. 12 12 13 13 == Description == … … 141 141 #### Links 142 142 143 * **<a href="https://fifu.app/">FIFU PRO (€29.90)</a>**143 * **<a href="https://fifu.app/">FIFU PRO</a>** 144 144 * **<a href="https://tastewp.com/new?pre-installed-plugin-slug=featured-image-from-url&redirect=admin.php%3Fpage%3Dfeatured-image-from-url&ni=true">Dummy site for testing</a>** 145 145 * **<a href="https://chrome.google.com/webstore/detail/fifu-scraper/pccimcccbkdeeadhejdmnffmllpicola">Extension for Google Chrome</a>** … … 247 247 == Changelog == 248 248 249 = 5.2.7 = 250 * New: Notice to rate the plugin; Enhancement: Auto set featured media from post content (now supports local relative URLs); Fix: Incomplete product data generated for Rich Results. 251 249 252 = 5.2.6 = 250 253 * Enhancement: improved integration with Rich Results from Google; Enhancement: alternative text can now be displayed as captions at the bottom of the image; Fix: images defined by other plugins were being displayed on social media instead of the remote featured image; Fix: Elementor widget not working with newer Elementor versions. … … 280 283 == Upgrade Notice == 281 284 282 = 5.2. 6=283 * Enhancement: improved integration with Rich Results from Google; Enhancement: alternative text can now be displayed as captions at the bottom of the image; Fix: images defined by other plugins were being displayed on social media instead of the remote featured image; Fix: Elementor widget not working with newer Elementor versions.285 = 5.2.7 = 286 * New: Notice to rate the plugin; Enhancement: Auto set featured media from post content (now supports local relative URLs); Fix: Incomplete product data generated for Rich Results.
Note: See TracChangeset
for help on using the changeset viewer.