| 1 |
<?php |
| 2 |
|
| 3 |
namespace BetterLinks\Admin; |
| 4 |
if ( ! defined( 'ABSPATH' ) ) { exit; } |
| 5 |
|
| 6 |
use BetterLinks\Helper; |
| 7 |
|
| 8 |
class Assets |
| 9 |
{ |
| 10 |
public function __construct() |
| 11 |
{ |
| 12 |
add_action('admin_enqueue_scripts', [$this, 'plugin_scripts']); |
| 13 |
add_action('enqueue_block_editor_assets', [$this, 'block_editor_assets']); |
| 14 |
add_filter( 'fluent_boards/asset_listed_slugs', function($approvedSlugs) { |
| 15 |
return wp_parse_args( [ 'betterlinks-intflboards' ], $approvedSlugs ); |
| 16 |
}); |
| 17 |
} |
| 18 |
|
| 19 |
/** |
| 20 |
* Enqueue Files on Start Plugin |
| 21 |
* |
| 22 |
* @function plugin_script |
| 23 |
*/ |
| 24 |
public function plugin_scripts($hook) |
| 25 |
{ |
| 26 |
if (\BetterLinks\Helper::plugin_page_hook_suffix($hook)) { |
| 27 |
add_action( |
| 28 |
'wp_print_scripts', |
| 29 |
function () { |
| 30 |
$isSkip = apply_filters('BetterLinks/Admin/skip_no_conflict', false); |
| 31 |
|
| 32 |
if ($isSkip) { |
| 33 |
return; |
| 34 |
} |
| 35 |
|
| 36 |
global $wp_scripts; |
| 37 |
if (!$wp_scripts) { |
| 38 |
return; |
| 39 |
} |
| 40 |
|
| 41 |
$pluginUrl = plugins_url(); |
| 42 |
foreach ($wp_scripts->queue as $script) { |
| 43 |
$src = $wp_scripts->registered[$script]->src; |
| 44 |
if (strpos($src, $pluginUrl) !== false && !strpos($src, BETTERLINKS_PLUGIN_SLUG) !== false) { |
| 45 |
wp_dequeue_script($wp_scripts->registered[$script]->handle); |
| 46 |
} |
| 47 |
} |
| 48 |
}, |
| 49 |
1 |
| 50 |
); |
| 51 |
$dependencies = include_once BETTERLINKS_ASSETS_DIR_PATH . 'js/betterlinks.core.min.asset.php'; |
| 52 |
// Version the stylesheet from its own mtime, not from the JS bundle |
| 53 |
// hash: a build that only changes SCSS leaves that hash untouched, |
| 54 |
// so browsers kept serving stale CSS and style fixes looked like |
| 55 |
// they had no effect. |
| 56 |
$admin_style_path = BETTERLINKS_ASSETS_DIR_PATH . 'css/betterlinks.css'; |
| 57 |
$admin_style_ver = file_exists($admin_style_path) ? (string) filemtime($admin_style_path) : $dependencies['version']; |
| 58 |
wp_enqueue_style('betterlinks-admin-style', BETTERLINKS_ASSETS_URI . 'css/betterlinks.css', [], $admin_style_ver, 'all'); |
| 59 |
wp_enqueue_script( |
| 60 |
'betterlinks-admin-core', |
| 61 |
BETTERLINKS_ASSETS_URI . 'js/betterlinks.core.min.js', |
| 62 |
array_merge($dependencies['dependencies'], ['regenerator-runtime']), |
| 63 |
$dependencies['version'], |
| 64 |
true |
| 65 |
); |
| 66 |
global $betterlinks_settings; |
| 67 |
$prefix = !empty($betterlinks_settings['prefix']) ? $betterlinks_settings['prefix'] : ''; |
| 68 |
wp_localize_script('betterlinks-admin-core', 'betterLinksGlobal', [ |
| 69 |
'betterlinks_nonce' => wp_create_nonce('betterlinks_admin_nonce'), |
| 70 |
'nonce' => wp_create_nonce('wp_rest'), |
| 71 |
'rest_url' => rest_url(), |
| 72 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 73 |
'namespace' => BETTERLINKS_PLUGIN_SLUG . '/v1/', |
| 74 |
'plugin_root_url' => BETTERLINKS_PLUGIN_ROOT_URI, |
| 75 |
'plugin_root_path' => BETTERLINKS_ROOT_DIR_PATH, |
| 76 |
'site_url' => apply_filters('betterlinks/site_url', site_url()), |
| 77 |
'route_path' => wp_parse_url(admin_url(), PHP_URL_PATH), |
| 78 |
'exists_links_json' => BETTERLINKS_EXISTS_LINKS_JSON, |
| 79 |
'exists_clicks_json' => BETTERLINKS_EXISTS_CLICKS_JSON, |
| 80 |
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only page slug used to bootstrap admin assets, no state mutation. |
| 81 |
'page' => isset($_GET['page']) ? sanitize_text_field(wp_unslash( $_GET['page'] )) : '', |
| 82 |
'is_pro_enabled' => apply_filters('betterlinks/pro_enabled', false), |
| 83 |
'prefix' => $prefix, |
| 84 |
'betterlinkspro_version' => defined('BETTERLINKS_PRO_VERSION') ? BETTERLINKS_PRO_VERSION : null, |
| 85 |
'is_extra_data_tracking_compatible' => apply_filters('betterlinks/is_extra_data_tracking_compatible', false), |
| 86 |
'menu_notice' => defined('BETTERLINKS_MENU_NOTICE') ? BETTERLINKS_MENU_NOTICE : null, |
| 87 |
'betterlinks_custom_domain_menu' => get_option( BETTERLINKS_CUSTOM_DOMAIN_MENU, 0 ), |
| 88 |
'betterlinks_settings' => $betterlinks_settings, |
| 89 |
// Quick Link Creation credential. No longer md5(AUTH_KEY): that was a |
| 90 |
// site-wide secret with no user binding, no expiry and no way to |
| 91 |
// revoke it from the plugin. This is a per-user, expiring, |
| 92 |
// revocable token issued by \BetterLinks\CLEToken. |
| 93 |
'betterlinks_auth' => \BetterLinks\Helper::get_cle_token_for_display(), |
| 94 |
'betterlinks_cle_endpoint' => rest_url(BETTERLINKS_PLUGIN_SLUG . '/v1/quick-link'), |
| 95 |
'betterlinks_date_format' => get_option( 'date_format' ), |
| 96 |
'is_fbs_enabled' => defined('FLUENT_BOARDS'), |
| 97 |
'betterlinks_quick_setup_step' => get_option( 'betterlinks_quick_setup_step', false ), |
| 98 |
'migratable_plugins' => Helper::get_migratable_plugins(), |
| 99 |
// Add user permission information for free version |
| 100 |
'user_can_manage_options' => current_user_can('manage_options'), |
| 101 |
// Term IDs that cannot be edited/deleted in the UI (Uncategorized + extensions). |
| 102 |
'protected_term_ids' => array_values(array_map('intval', (array) apply_filters('betterlinks/protected_term_ids', array(1)))), |
| 103 |
// Categories a feature owns but keeps off Manage Links. The links query |
| 104 |
// already excludes them, but the board re-adds empty categories from the |
| 105 |
// /terms payload, so the SPA needs the same list to stay consistent. |
| 106 |
'dashboard_hidden_term_ids' => array_values(array_unique(array_filter(array_map('intval', (array) apply_filters('betterlinks/dashboard_hidden_term_ids', array(), (array) $betterlinks_settings))))), |
| 107 |
// MCP connector bootstrap. `abilities_api_available` is what tells |
| 108 |
// the MCP page whether the bundled runtime actually loaded — with |
| 109 |
// it missing, a client connects and is offered no tools at all. |
| 110 |
'mcp' => [ |
| 111 |
'abilities_api_available' => function_exists('wp_register_ability'), |
| 112 |
'endpoint' => home_url('/betterlinks/mcp'), |
| 113 |
], |
| 114 |
]); |
| 115 |
|
| 116 |
$menu_notice = get_option('betterlinks_menu_notice', 0); |
| 117 |
if( defined( 'BETTERLINKS_MENU_NOTICE' ) && BETTERLINKS_MENU_NOTICE !== $menu_notice ) { |
| 118 |
update_option('betterlinks_menu_notice', BETTERLINKS_MENU_NOTICE); |
| 119 |
} |
| 120 |
} |
| 121 |
wp_set_script_translations('betterlinks-admin-core', 'betterlinks', BETTERLINKS_ROOT_DIR_PATH . 'languages/'); |
| 122 |
if ( ! in_array( $hook, ['post.php', 'post-new.php'] ) ) { |
| 123 |
// Version from the file's mtime (not BETTERLINKS_VERSION) so CSS-only |
| 124 |
// edits invalidate the browser cache — same reason as betterlinks.css above. |
| 125 |
$notice_style_path = BETTERLINKS_ASSETS_DIR_PATH . 'css/betterlinks-admin-notice.css'; |
| 126 |
$notice_style_ver = file_exists($notice_style_path) ? (string) filemtime($notice_style_path) : BETTERLINKS_VERSION; |
| 127 |
wp_enqueue_style('betterlinks-admin-notice', BETTERLINKS_ASSETS_URI . 'css/betterlinks-admin-notice.css', [], $notice_style_ver, 'all'); |
| 128 |
} |
| 129 |
if( 'toplevel_page_fluent-boards' == $hook ){ |
| 130 |
$dependencies = include_once BETTERLINKS_ASSETS_DIR_PATH . 'js/betterlinks-intflboards.core.min.asset.php'; |
| 131 |
wp_enqueue_script( |
| 132 |
'betterlinks-intflboards', |
| 133 |
BETTERLINKS_ASSETS_URI . 'js/betterlinks-intflboards.core.min.js', |
| 134 |
array_merge($dependencies['dependencies'], ['regenerator-runtime']), |
| 135 |
$dependencies['version'], |
| 136 |
[ |
| 137 |
'in_footer' => true, |
| 138 |
] |
| 139 |
); |
| 140 |
$settings = Cache::get_json_settings(); |
| 141 |
wp_localize_script('betterlinks-intflboards', 'betterLinksFlbIntegration', [ |
| 142 |
'plugin_root_url' => BETTERLINKS_PLUGIN_ROOT_URI, |
| 143 |
'TASKS' => 'tasks/', |
| 144 |
'betterlinks_nonce' => wp_create_nonce('betterlinks_admin_nonce'), |
| 145 |
'site_url' => apply_filters('betterlinks/site_url', site_url()), |
| 146 |
'admin_url' => admin_url('/admin.php'), |
| 147 |
'fbs_settings' => isset($settings['fbs']) ? $settings['fbs'] : null |
| 148 |
]); |
| 149 |
wp_enqueue_style('betterlinks-intflboards', BETTERLINKS_ASSETS_URI . 'css/integrations/btl-fbs.css', [], $dependencies['version'], 'all'); |
| 150 |
} |
| 151 |
} |
| 152 |
|
| 153 |
/** |
| 154 |
* Enqueue Guten Scripts |
| 155 |
*/ |
| 156 |
public function block_editor_assets() |
| 157 |
{ |
| 158 |
global $pagenow; |
| 159 |
if( 'customize.php' === $pagenow ) return; |
| 160 |
global $betterlinks_settings; |
| 161 |
|
| 162 |
$is_allow_gutenberg = isset( $betterlinks_settings['is_allow_gutenberg'] ) ? $betterlinks_settings['is_allow_gutenberg'] : false; |
| 163 |
$affiliate_link_disclosure = isset( $betterlinks_settings['affiliate_link_disclosure'] ) ? $betterlinks_settings['affiliate_link_disclosure'] : false; |
| 164 |
$enable_auto_link = isset( $betterlinks_settings['enable_auto_link'] ) ? $betterlinks_settings['enable_auto_link'] : false; |
| 165 |
|
| 166 |
if( !($is_allow_gutenberg || $affiliate_link_disclosure || $enable_auto_link) ) return; |
| 167 |
|
| 168 |
$dependencies = include_once BETTERLINKS_ASSETS_DIR_PATH . 'js/betterlinks-gutenberg.core.min.asset.php'; |
| 169 |
wp_enqueue_style( |
| 170 |
'betterlinks-gutenberg', |
| 171 |
BETTERLINKS_ASSETS_URI . 'css/betterlinks-gutenberg.css', |
| 172 |
[], |
| 173 |
$dependencies['version'] |
| 174 |
); |
| 175 |
|
| 176 |
wp_enqueue_script( |
| 177 |
'betterlinks-gutenberg', |
| 178 |
BETTERLINKS_ASSETS_URI . 'js/betterlinks-gutenberg.core.min.js', |
| 179 |
array_merge($dependencies['dependencies'], ['regenerator-runtime']), |
| 180 |
filemtime(BETTERLINKS_ASSETS_DIR_PATH . 'js/betterlinks-gutenberg.core.min.js'), |
| 181 |
true |
| 182 |
); |
| 183 |
|
| 184 |
|
| 185 |
$prefix = isset($betterlinks_settings['prefix']) ? $betterlinks_settings['prefix'] : ''; |
| 186 |
wp_localize_script('betterlinks-gutenberg', 'betterLinksGlobal', [ |
| 187 |
'post_type' => get_post_type(), |
| 188 |
'betterlinks_nonce' => wp_create_nonce('betterlinks_admin_nonce'), |
| 189 |
'nonce' => wp_create_nonce('wp_rest'), |
| 190 |
'rest_url' => rest_url(), |
| 191 |
// Needed by AJAX helpers used in the block editor (e.g. shortURLUniqueCheckGutenberg |
| 192 |
// in the AutoLink sidebar); without it those calls logged "ajaxurl is not defined". |
| 193 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 194 |
'namespace' => BETTERLINKS_PLUGIN_SLUG . '/v1/', |
| 195 |
'plugin_root_url' => BETTERLINKS_PLUGIN_ROOT_URI, |
| 196 |
'plugin_root_path' => BETTERLINKS_ROOT_DIR_PATH, |
| 197 |
'site_url' => apply_filters('betterlinks/site_url', site_url()), |
| 198 |
'actual_site_url' => site_url(), |
| 199 |
'route_path' => wp_parse_url(admin_url(), PHP_URL_PATH), |
| 200 |
'is_pro_enabled' => apply_filters('betterlinks/pro_enabled', false), |
| 201 |
// Needed by pro_version_check() in the editor (e.g. the AI Link Assistant |
| 202 |
// 2.8.0+ gate). Without it the check falls back to its "no Pro" early-return. |
| 203 |
'betterlinkspro_version' => defined('BETTERLINKS_PRO_VERSION') ? BETTERLINKS_PRO_VERSION : null, |
| 204 |
'prefix' => $prefix, |
| 205 |
'betterlinks_settings' => $betterlinks_settings, |
| 206 |
// Add user permission information for free version |
| 207 |
'user_can_manage_options' => current_user_can('manage_options'), |
| 208 |
// Categories a feature owns but keeps off Manage Links (the bio pages' |
| 209 |
// "Link in Bio", Fluent Boards' task category). The editor sidebar needs |
| 210 |
// the same list the dashboard query uses: a link filed under one of these |
| 211 |
// saves correctly but never appears on Manage Links, so Instant Redirect |
| 212 |
// must neither offer them nor fall back to one. |
| 213 |
'dashboard_hidden_term_ids' => array_values(array_unique(array_filter(array_map('intval', (array) apply_filters('betterlinks/dashboard_hidden_term_ids', array(), (array) $betterlinks_settings))))), |
| 214 |
]); |
| 215 |
wp_set_script_translations('betterlinks-gutenberg', 'betterlinks', BETTERLINKS_ROOT_DIR_PATH . 'languages/'); |
| 216 |
} |
| 217 |
} |
| 218 |
|