| 1 |
<?php |
| 2 |
/** |
| 3 |
* Plugin Name: Section Collection |
| 4 |
* Description: A versatile section collection plugin featuring essential UI blocks to craft impactful, engaging, and user-centric web pages. |
| 5 |
* Version: 2.0.2 |
| 6 |
* Author: bPlugins |
| 7 |
* Author URI: https://bplugins.com |
| 8 |
* License: GPLv3 |
| 9 |
* License URI: https://www.gnu.org/licenses/gpl-3.0.txt |
| 10 |
* Text Domain: section-collection |
| 11 |
* |
| 12 |
* Premium-only code. Freemius strips these paths when generating the free |
| 13 |
* wordpress.org build, so no Pro section code ships to free users. The full |
| 14 |
* Freemius SDK is premium-only too; the free build ships the lite SDK instead. |
| 15 |
*/ |
| 16 |
|
| 17 |
// ABS PATH |
| 18 |
if ( !defined( 'ABSPATH' ) ) { exit; } |
| 19 |
|
| 20 |
/* |
| 21 |
* Free + Pro both active → bail to avoid a fatal, and keep Pro. |
| 22 |
* |
| 23 |
* The free (wordpress.org) and Pro (Freemius) builds ship the same constants, |
| 24 |
* functions and classes. If both are active, the second one to load throws a |
| 25 |
* fatal "cannot redeclare" error before Freemius can swap them — which is what |
| 26 |
* happens when someone activates Pro while the free version is still active. |
| 27 |
* |
| 28 |
* Here, if another Section Collection copy already loaded this request, we bail |
| 29 |
* before redeclaring anything (no fatal) and then deactivate the free copy so |
| 30 |
* the Pro build takes over. If THIS copy is the free one, it deactivates itself. |
| 31 |
*/ |
| 32 |
if ( defined( 'BPSC_PLUGIN_VERSION' ) ) { |
| 33 |
$bpsc_dup_file = __FILE__; |
| 34 |
add_action( 'admin_init', function () use ( $bpsc_dup_file ) { |
| 35 |
if ( ! function_exists( 'deactivate_plugins' ) ) { |
| 36 |
require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 37 |
} |
| 38 |
$self = plugin_basename( $bpsc_dup_file ); |
| 39 |
$is_premium = file_exists( plugin_dir_path( $bpsc_dup_file ) . 'vendor/freemius/start.php' ); |
| 40 |
$main_file = '/section-collection.php'; |
| 41 |
|
| 42 |
if ( $is_premium ) { |
| 43 |
// Pro wins — deactivate every OTHER (free) Section Collection copy. |
| 44 |
foreach ( (array) get_option( 'active_plugins', array() ) as $plugin ) { |
| 45 |
if ( $plugin !== $self && substr( $plugin, - strlen( $main_file ) ) === $main_file ) { |
| 46 |
deactivate_plugins( $plugin ); |
| 47 |
} |
| 48 |
} |
| 49 |
} else { |
| 50 |
// This free copy is the duplicate — deactivate itself so Pro stays. |
| 51 |
deactivate_plugins( $self ); |
| 52 |
} |
| 53 |
} ); |
| 54 |
return; |
| 55 |
} |
| 56 |
|
| 57 |
// Constant |
| 58 |
$bpsc_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : ''; |
| 59 |
$bpsc_is_local = $bpsc_host && ( preg_match( '/^(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/', $bpsc_host ) || preg_match( '/\.(local|test)(:\d+)?$/', $bpsc_host ) ); |
| 60 |
// Real plugin version (for display). BPSC_VERSION is the asset cache-bust |
| 61 |
// token — it becomes time() locally so dev builds always reload. |
| 62 |
define( 'BPSC_PLUGIN_VERSION', '2.0.2' ); |
| 63 |
define( 'BPSC_VERSION', $bpsc_is_local ? (string) time() : BPSC_PLUGIN_VERSION ); |
| 64 |
define( 'BPSC_DIR_URL', plugin_dir_url( __FILE__ ) ); |
| 65 |
define( 'BPSC_DIR_PATH', plugin_dir_path( __FILE__ ) ); |
| 66 |
|
| 67 |
// True only when the premium build is installed. Freemius strips the full SDK |
| 68 |
// (vendor/freemius) from the free wordpress.org build and ships vendor/freemius-lite |
| 69 |
// instead, so the full SDK's presence is what distinguishes the two builds. |
| 70 |
define( 'BPSC_HAS_PRO', file_exists( BPSC_DIR_PATH . 'vendor/freemius/start.php' ) ); |
| 71 |
|
| 72 |
// Freemius SDK. The init lives in includes/fs.php (full SDK, premium build) and |
| 73 |
// includes/fs-lite.php (lite SDK, free wordpress.org build). Both define sc_fs(). |
| 74 |
if ( function_exists( 'sc_fs' ) ) { |
| 75 |
sc_fs()->set_basename( BPSC_HAS_PRO, __FILE__ ); |
| 76 |
} else { |
| 77 |
if ( BPSC_HAS_PRO ) { |
| 78 |
require_once BPSC_DIR_PATH . 'includes/fs.php'; |
| 79 |
} else { |
| 80 |
require_once BPSC_DIR_PATH . 'includes/fs-lite.php'; |
| 81 |
} |
| 82 |
|
| 83 |
// Remove the Freemius "Add-Ons" item (admin.php?page=section-collection-addons) |
| 84 |
// from the Section Collection sidebar. Freemius still registers the page even |
| 85 |
// when its visibility filter returns false (and re-shows it whenever you're on |
| 86 |
// that page), so we drop the menu link after Freemius builds the menu — it hooks |
| 87 |
// admin_menu at WP_FS__LOWEST_PRIORITY (999999999) — and redirect direct hits. |
| 88 |
add_action( 'admin_menu', function () { |
| 89 |
remove_submenu_page( 'section-collection', 'section-collection-addons' ); |
| 90 |
}, PHP_INT_MAX ); |
| 91 |
|
| 92 |
add_action( 'admin_init', function () { |
| 93 |
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only menu gate, no state change. |
| 94 |
if ( isset( $_GET['page'] ) && 'section-collection-addons' === sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) { |
| 95 |
wp_safe_redirect( admin_url( 'admin.php?page=section-collection' ) ); |
| 96 |
exit; |
| 97 |
} |
| 98 |
} ); |
| 99 |
} |
| 100 |
|
| 101 |
/** |
| 102 |
* Whether the current site can use Pro sections. |
| 103 |
* |
| 104 |
* True when the user holds a valid premium license (the all-access Premium |
| 105 |
* plan). Safe to call even if the SDK failed to load. |
| 106 |
* |
| 107 |
* @return bool |
| 108 |
*/ |
| 109 |
// sc_can_use_pro / sc_can_use_section (and their matching filters) are the |
| 110 |
// plugin's documented public API — users hook `add_filter( 'sc_can_use_pro', … )` |
| 111 |
// — and `sc_` is the plugin prefix. Renaming would break existing user code. |
| 112 |
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals |
| 113 |
if ( ! function_exists( 'sc_can_use_pro' ) ) { |
| 114 |
function sc_can_use_pro() { |
| 115 |
$can = function_exists( 'sc_fs' ) && sc_fs()->can_use_premium_code(); |
| 116 |
|
| 117 |
/** |
| 118 |
* Filter whether the site can use Pro sections. |
| 119 |
* |
| 120 |
* Handy for testing the unlocked (paid) state without a live license, e.g. |
| 121 |
* drop this in a snippet / wp-config: |
| 122 |
* add_filter( 'sc_can_use_pro', '__return_true' ); |
| 123 |
* |
| 124 |
* @param bool $can Whether Pro sections are unlocked. |
| 125 |
*/ |
| 126 |
return (bool) apply_filters( 'sc_can_use_pro', $can ); |
| 127 |
} |
| 128 |
} |
| 129 |
|
| 130 |
/** |
| 131 |
* Whether the current site can use a specific Pro section. |
| 132 |
* |
| 133 |
* Unlocked when the site holds the all-access Premium license, OR has bought |
| 134 |
* the section's individual Freemius add-on (à-la-carte). |
| 135 |
* |
| 136 |
* @param int|string $addon_id Freemius add-on product id for the section. |
| 137 |
* @return bool |
| 138 |
*/ |
| 139 |
if ( ! function_exists( 'sc_can_use_section' ) ) { |
| 140 |
function sc_can_use_section( $addon_id = 0 ) { |
| 141 |
$can = false; |
| 142 |
|
| 143 |
if ( function_exists( 'sc_fs' ) ) { |
| 144 |
$fs = sc_fs(); |
| 145 |
|
| 146 |
// All-access Premium unlocks every section. |
| 147 |
if ( $fs->can_use_premium_code() ) { |
| 148 |
$can = true; |
| 149 |
} |
| 150 |
|
| 151 |
// Per-add-on (à-la-carte). Only meaningful once the site is connected. |
| 152 |
// `is_registered()` exists only on the full Freemius SDK, not the Lite SDK |
| 153 |
// in the free build — guard it so the free build never fatals here. |
| 154 |
if ( ! $can && $addon_id && method_exists( $fs, 'is_registered' ) && $fs->is_registered() ) { |
| 155 |
// If the add-on is installed as its own plugin, use its license. |
| 156 |
if ( method_exists( $fs, 'get_addon_instance' ) ) { |
| 157 |
$inst = $fs->get_addon_instance( $addon_id ); |
| 158 |
if ( $inst && $inst->can_use_premium_code() ) { |
| 159 |
$can = true; |
| 160 |
} |
| 161 |
} |
| 162 |
|
| 163 |
// Otherwise, recognise an add-on purchased against this account. |
| 164 |
if ( ! $can && method_exists( $fs, 'get_account_addons' ) ) { |
| 165 |
$owned = $fs->get_account_addons(); |
| 166 |
if ( is_array( $owned ) && in_array( (string) $addon_id, array_map( 'strval', $owned ), true ) ) { |
| 167 |
$can = true; |
| 168 |
} |
| 169 |
} |
| 170 |
} |
| 171 |
} |
| 172 |
|
| 173 |
/** |
| 174 |
* Filter whether the current site can use a given Pro section. |
| 175 |
* |
| 176 |
* Handy for testing the unlock without a live purchase, e.g.: |
| 177 |
* add_filter( 'sc_can_use_section', '__return_true' ); |
| 178 |
* |
| 179 |
* @param bool $can Whether the section is unlocked. |
| 180 |
* @param int|string $addon_id The section's Freemius add-on id. |
| 181 |
*/ |
| 182 |
return (bool) apply_filters( 'sc_can_use_section', $can, $addon_id ); |
| 183 |
} |
| 184 |
} |
| 185 |
// phpcs:enable WordPress.NamingConventions.PrefixAllGlobals |
| 186 |
|
| 187 |
// Admin dashboard (top-level menu + React SPA). |
| 188 |
require_once BPSC_DIR_PATH . 'includes/Dashboard.php'; |
| 189 |
|
| 190 |
// Template Library (editor toolbar browser + bBlocks dependency manager). |
| 191 |
require_once BPSC_DIR_PATH . 'includes/Templates/Templates.php'; |
| 192 |
|
| 193 |
// Premium-only files. These are stripped from the free wordpress.org build |
| 194 |
// (see @fs_premium_only in the header), so guard each require with file_exists |
| 195 |
// so the free build never fatals on a missing file. |
| 196 |
if ( file_exists( BPSC_DIR_PATH . 'includes/pro/pro-blocks.php' ) ) { |
| 197 |
require_once BPSC_DIR_PATH . 'includes/pro/pro-blocks.php'; |
| 198 |
} |
| 199 |
// License activation (dashboard "Activation" page AJAX) — Pro only. |
| 200 |
if ( file_exists( BPSC_DIR_PATH . 'includes/LicenseActivation.php' ) ) { |
| 201 |
require_once BPSC_DIR_PATH . 'includes/LicenseActivation.php'; |
| 202 |
} |
| 203 |
|
| 204 |
|
| 205 |
|
| 206 |
if( !class_exists( 'BPSCPlugin' ) ){ |
| 207 |
class BPSCPlugin{ |
| 208 |
function __construct(){ |
| 209 |
add_action( 'init', [ $this, 'onInit' ] ); |
| 210 |
add_filter( 'block_editor_settings_all', [ $this, 'addLeafletEditorIframeStyle' ] ); |
| 211 |
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueueAssets' ] ); |
| 212 |
add_action( 'wp_enqueue_scripts', [ $this, 'enqueueScripts' ] ); |
| 213 |
add_action( 'wp_enqueue_scripts', [ $this, 'enqueueLeaflet' ] ); |
| 214 |
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueueLeaflet' ] ); |
| 215 |
add_filter( 'block_categories_all', [$this, 'registerCategories'] ); |
| 216 |
} |
| 217 |
|
| 218 |
function onInit(){ |
| 219 |
$blocks =['testimonial_block', 'timeline_block', 'ticker', 'about-us', 'team-section', 'faq', 'call-to-actions', 'info-list-block', 'hero-section', 'pricing-table-section', 'feature-details', 'info-grid', 'feature-overview-section', 'modern-faq-section', "money-back-guarantee-card", "flip-box-section", "service-section", "counter-section", "fancy-image-box-section", "floating-image-section", "brand-sponsor-section", "slider-section", "mission-and-vision-section", "masonry-image-carousel", "multi-tab-timeline-section", "image-comparison-section", "video-showcase-section", "chart-section", "progress-section", "storytelling-section", "recommendation-section", "filterable-showcase-section", "carousel-testimonial-section", "resource-download-section","snippet-copy-section", "floating-cta-section", "orbiting-team-section", "map-section", "schedule-section", "how-it-works-section", "open-positions-section", "pricing-toggle-section", "social-proof-wall-section", "awards-recognition-section", "tabbed-feature-showcase-section", "food-menu-section", "roi-calculator-section", "press-mentions-section", "project-portfolio-section", "lead-quiz-section", "announcement-bar-section"]; |
| 220 |
// Sections turned off from the dashboard Blocks page are skipped. |
| 221 |
$disabled = (array) get_option( 'bpscDisabledBlocks', [] ); |
| 222 |
|
| 223 |
foreach ( $blocks as $block ) { |
| 224 |
$blockJson = __DIR__ . "/build/{$block}/block.json"; |
| 225 |
|
| 226 |
if ( $disabled && file_exists( $blockJson ) ) { |
| 227 |
$meta = json_decode( (string) file_get_contents( $blockJson ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- reading a bundled local block.json. |
| 228 |
if ( isset( $meta['name'] ) && in_array( $meta['name'], $disabled, true ) ) { |
| 229 |
continue; |
| 230 |
} |
| 231 |
} |
| 232 |
|
| 233 |
register_block_type( __DIR__ . "/build/".$block ); |
| 234 |
} |
| 235 |
} |
| 236 |
function enqueueAssets(){ |
| 237 |
wp_enqueue_style( 'bndl-style', BPSC_DIR_URL . 'build/index.css', [], BPSC_VERSION ); |
| 238 |
wp_enqueue_script( 'bndl-script', BPSC_DIR_URL . 'build/index.js', ['wp-blocks'], BPSC_VERSION, true ); |
| 239 |
|
| 240 |
// Expose the disabled-blocks list to the editor. Every block bundle |
| 241 |
// (free build/index.js and Pro build/pro/index.js) registers all of |
| 242 |
// its blocks client-side, so the server-side register_block_type skip |
| 243 |
// alone doesn't hide a disabled block in the editor — the bundles read |
| 244 |
// this global and unregister the disabled ones. Attached to wp-blocks |
| 245 |
// (a dependency of both bundles) so it's set before either runs. |
| 246 |
$disabled = array_values( (array) get_option( 'bpscDisabledBlocks', [] ) ); |
| 247 |
wp_add_inline_script( |
| 248 |
'wp-blocks', |
| 249 |
'window.bpscDisabledBlocks = ' . wp_json_encode( $disabled ) . ';', |
| 250 |
'after' |
| 251 |
); |
| 252 |
|
| 253 |
$this->enqueueTemplateLibrary(); |
| 254 |
} |
| 255 |
|
| 256 |
// Template Library: editor toolbar browser + bBlocks dependency manager. |
| 257 |
function enqueueTemplateLibrary(){ |
| 258 |
$bblocks = \SectionCollection\Inc\Templates\Templates::status_array(); |
| 259 |
|
| 260 |
// When bBlocks is active it renders its own Template Library button. |
| 261 |
// Don't load ours too — that would show a duplicate button. (Our |
| 262 |
// library exists mainly to bootstrap bBlocks when it's missing.) |
| 263 |
if ( ! empty( $bblocks['active'] ) ) { |
| 264 |
return; |
| 265 |
} |
| 266 |
|
| 267 |
$asset_file = BPSC_DIR_PATH . 'build/template-library.asset.php'; |
| 268 |
$asset = file_exists( $asset_file ) ? require $asset_file : [ 'dependencies' => [], 'version' => BPSC_VERSION ]; |
| 269 |
|
| 270 |
// wp.ajax (imperative AJAX) is a global, not an import, so webpack |
| 271 |
// won't list wp-util/jquery — add the runtime globals explicitly. |
| 272 |
$deps = array_values( array_unique( array_merge( |
| 273 |
$asset['dependencies'], |
| 274 |
[ 'wp-util', 'wp-data', 'wp-dom-ready', 'wp-blocks', 'wp-block-editor', 'wp-components', 'wp-i18n', 'jquery' ] |
| 275 |
) ) ); |
| 276 |
|
| 277 |
wp_enqueue_script( 'bpsc-template-library', BPSC_DIR_URL . 'build/template-library.js', $deps, $asset['version'], false ); |
| 278 |
wp_set_script_translations( 'bpsc-template-library', 'section-collection', BPSC_DIR_PATH . 'languages' ); |
| 279 |
|
| 280 |
if ( file_exists( BPSC_DIR_PATH . 'build/template-library.css' ) ) { |
| 281 |
wp_enqueue_style( 'bpsc-template-library', BPSC_DIR_URL . 'build/template-library.css', [], $asset['version'] ); |
| 282 |
} |
| 283 |
|
| 284 |
wp_localize_script( 'bpsc-template-library', 'scTemplateLibrary', [ |
| 285 |
'nonce' => wp_create_nonce( 'wp_ajax' ), |
| 286 |
'ajaxUrl' => admin_url( 'admin-ajax.php' ), |
| 287 |
'isPremium' => function_exists( 'sc_can_use_pro' ) ? sc_can_use_pro() : false, |
| 288 |
'pricingUrl' => admin_url( 'admin.php?page=section-collection#/pricing' ), |
| 289 |
'logo' => BPSC_DIR_URL . 'assets/logo.svg', |
| 290 |
'bblocks' => $bblocks, |
| 291 |
] ); |
| 292 |
} |
| 293 |
|
| 294 |
function enqueueScripts(){ |
| 295 |
wp_enqueue_script( 'bndl-advanced-script', BPSC_DIR_URL . 'build/advanced.js', [], BPSC_VERSION, true ); |
| 296 |
} |
| 297 |
|
| 298 |
function registerCategories( $categories ){ |
| 299 |
return array_merge( [ [ |
| 300 |
'slug' => 'bPlugins', |
| 301 |
'title' => __( 'Section Collection', 'section-collection' ), |
| 302 |
] ], $categories ); |
| 303 |
} |
| 304 |
function enqueueLeaflet() { |
| 305 |
// is_admin() covers the block editor. On the frontend we also check |
| 306 |
// the full template (FSE template parts / synced patterns), since |
| 307 |
// has_block() on post content alone can miss blocks placed there. |
| 308 |
$has_map = is_admin() || has_block( 'bpsc/map-section' ); |
| 309 |
|
| 310 |
if ( ! $has_map && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) { |
| 311 |
global $_wp_current_template_content; |
| 312 |
if ( ! empty( $_wp_current_template_content ) && has_block( 'bpsc/map-section', $_wp_current_template_content ) ) { |
| 313 |
$has_map = true; |
| 314 |
} |
| 315 |
} |
| 316 |
|
| 317 |
if ( $has_map ) { |
| 318 |
$leaflet_js = BPSC_DIR_PATH . 'assets/leaflet/leaflet.js'; |
| 319 |
$leaflet_css = BPSC_DIR_PATH . 'assets/leaflet/leaflet.css'; |
| 320 |
$has_local = file_exists( $leaflet_js ) && file_exists( $leaflet_css ); |
| 321 |
|
| 322 |
if ( file_exists( $leaflet_css ) ) { |
| 323 |
wp_enqueue_style( |
| 324 |
'leaflet', |
| 325 |
BPSC_DIR_URL . 'assets/leaflet/leaflet.css', |
| 326 |
[], |
| 327 |
'1.9.4' |
| 328 |
); |
| 329 |
} |
| 330 |
if ( file_exists( $leaflet_js ) ) { |
| 331 |
wp_enqueue_script( |
| 332 |
'leaflet', |
| 333 |
BPSC_DIR_URL . 'assets/leaflet/leaflet.js', |
| 334 |
[], |
| 335 |
'1.9.4', |
| 336 |
true |
| 337 |
); |
| 338 |
} |
| 339 |
|
| 340 |
// Safety net: if the locally bundled Leaflet is unavailable (so |
| 341 |
// window.L never loaded), pull it from the public CDN at runtime so |
| 342 |
// the Map block still renders. The URL lives in a JS string (not in |
| 343 |
// a wp_enqueue_* call), so no asset is offloaded by the plugin. |
| 344 |
if ( ! $has_local ) { |
| 345 |
add_action( 'wp_footer', [ $this, 'printLeafletFallback' ], 5 ); |
| 346 |
add_action( 'admin_footer', [ $this, 'printLeafletFallback' ], 5 ); |
| 347 |
} |
| 348 |
} |
| 349 |
} |
| 350 |
|
| 351 |
/** |
| 352 |
* Runtime fallback that injects Leaflet from the CDN only when the locally |
| 353 |
* bundled copy is missing. Kept out of the asset-enqueue system on purpose. |
| 354 |
*/ |
| 355 |
function printLeafletFallback() { |
| 356 |
$css = esc_url( 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css' ); |
| 357 |
$js = esc_url( 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js' ); |
| 358 |
?> |
| 359 |
<script> |
| 360 |
( function () { |
| 361 |
if ( window.L ) { return; } |
| 362 |
var c = document.createElement( 'link' ); |
| 363 |
c.rel = 'stylesheet'; |
| 364 |
c.href = <?php echo wp_json_encode( $css ); ?>; |
| 365 |
document.head.appendChild( c ); |
| 366 |
var s = document.createElement( 'script' ); |
| 367 |
s.src = <?php echo wp_json_encode( $js ); ?>; |
| 368 |
document.head.appendChild( s ); |
| 369 |
} )(); |
| 370 |
</script> |
| 371 |
<?php |
| 372 |
} |
| 373 |
|
| 374 |
/** |
| 375 |
* The modern block editor renders the canvas inside an iframe with its own |
| 376 |
* document. Styles enqueued via enqueue_block_editor_assets land in the |
| 377 |
* OUTER page, not the iframe, so Leaflet's CSS never reaches the map and |
| 378 |
* tiles render unstyled/scattered in the editor. Injecting the bundled |
| 379 |
* Leaflet CSS through the editor settings 'styles' array places it inside |
| 380 |
* the iframe canvas, which is where the block (and therefore the map) |
| 381 |
* actually renders. |
| 382 |
*/ |
| 383 |
function addLeafletEditorIframeStyle( $settings ) { |
| 384 |
$leaflet_css_path = BPSC_DIR_PATH . 'assets/leaflet/leaflet.css'; |
| 385 |
if ( ! isset( $settings['styles'] ) || ! is_array( $settings['styles'] ) ) { |
| 386 |
$settings['styles'] = []; |
| 387 |
} |
| 388 |
if ( file_exists( $leaflet_css_path ) ) { |
| 389 |
$settings['styles'][] = [ |
| 390 |
'css' => file_get_contents( $leaflet_css_path ), // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading a bundled local CSS file. |
| 391 |
]; |
| 392 |
} else { |
| 393 |
// Fallback when the bundled CSS is unavailable. The URL lives in a |
| 394 |
// CSS @import string, not in a wp_enqueue_* call. |
| 395 |
$settings['styles'][] = [ |
| 396 |
'css' => "@import url('https://unpkg.com/leaflet@1.9.4/dist/leaflet.css');", |
| 397 |
]; |
| 398 |
} |
| 399 |
return $settings; |
| 400 |
} |
| 401 |
} |
| 402 |
|
| 403 |
|
| 404 |
new BPSCPlugin(); |
| 405 |
} |
| 406 |
|
| 407 |
|