| @@ -22,8 +22,21 @@ | ||
| 22 | 22 | // Assets Generator |
| 23 | 23 | add_action( 'save_post', [ $self, 'generate_block_assets' ], 10, 3 ); |
| 24 | 24 | add_action( 'switch_theme', [ $self, 'clear_generated_block_assets' ] ); |
| 25 | 25 | add_action( 'save_post', [ $self, 'download_google_fonts_locally' ], 20, 3 ); |
| 26 | + add_action( 'deleted_post', [ $self, 'flush_site_fonts_on_delete' ], 10, 2 ); | |
| 27 | + // Self-hosting template fonts discovered on a front-end request happens | |
| 28 | + // here, off the visitor's request. | |
| 29 | + add_action( 'ablocks/download_site_fonts', [ '\ABlocks\Classes\FontCollector', 'update_site_fonts' ] ); | |
| 30 | + // A theme swap changes which templates and template parts exist. | |
| 31 | + add_action( 'switch_theme', [ '\ABlocks\Classes\FontCollector', 'flush_site_fonts' ] ); | |
| 32 | + // PERF-2: pre-warm the page's generated assets in the background after save, | |
| 33 | + // so the first visitor doesn't pay the parse/generate/write cost. | |
| 34 | + add_action( 'save_post', [ $self, 'prewarm_page_assets' ], 30, 3 ); | |
| 35 | + // Recompute global typography fonts whenever the plugin's global settings change. | |
| 36 | + add_action( 'ablocks/after_save_settings', [ $self, 'refresh_global_fonts' ] ); | |
| 37 | + // Bust the cached global CSS variables when global settings change. | |
| 38 | + add_action( 'ablocks/after_save_settings', [ $self, 'clear_global_css_cache' ] ); | |
| 26 | 39 | |
| 27 | 40 | $self->register_block_sanitizer(); |
| 28 | 41 | $self->form_builder_default_data(); |
| 29 | 42 | } |
| @@ -79,8 +92,14 @@ | ||
| 79 | 92 | new \ABlocks\Blocks\StoreengineBillingInfo\Block(); |
| 80 | 93 | new \ABlocks\Blocks\StoreengineShippingInfo\Block(); |
| 81 | 94 | new \ABlocks\Blocks\StoreengineCartNotice\Block(); |
| 82 | 95 | new \ABlocks\Blocks\StoreengineOrderDetails\Block(); |
| 96 | + // Funnel Builder blocks (render the funnel shortcodes). | |
| 97 | + new \ABlocks\Blocks\StoreengineFunnelCheckout\Block(); | |
| 98 | + new \ABlocks\Blocks\StoreengineFunnelOffer\Block(); | |
| 99 | + new \ABlocks\Blocks\StoreengineFunnelAccept\Block(); | |
| 100 | + new \ABlocks\Blocks\StoreengineFunnelDecline\Block(); | |
| 101 | + new \ABlocks\Blocks\StoreengineFunnelContinue\Block(); | |
| 83 | 102 | new \ABlocks\Blocks\StoreengineMiniCart\Block(); |
| 84 | 103 | new \ABlocks\Blocks\StoreengineProductGallery\Block(); |
| 85 | 104 | new \ABlocks\Blocks\StoreengineProductSummary\Block(); |
| 86 | 105 | new \ABlocks\Blocks\StoreengineProductDescription\Block(); |
| @@ -85,11 +104,35 @@ | ||
| 85 | 104 | new \ABlocks\Blocks\StoreengineProductSummary\Block(); |
| 86 | 105 | new \ABlocks\Blocks\StoreengineProductDescription\Block(); |
| 87 | 106 | new \ABlocks\Blocks\StoreengineProductReview\Block(); |
| 88 | 107 | }//end if |
| 108 | + | |
| 109 | + if ( class_exists('EasyContentManager') ) { | |
| 110 | + // Easy Content Manager Register Block | |
| 111 | + new \ABlocks\Blocks\EcmBookmarkButton\Block(); | |
| 112 | + new \ABlocks\Blocks\EcmBookmarkBadge\Block(); | |
| 113 | + new \ABlocks\Blocks\EcmBookmarkList\Block(); | |
| 114 | + new \ABlocks\Blocks\EcmBookmarkCount\Block(); | |
| 115 | + new \ABlocks\Blocks\EcmReactionList\Block(); | |
| 116 | + new \ABlocks\Blocks\EcmReaction\Block(); | |
| 117 | + new \ABlocks\Blocks\EcmUpvote\Block(); | |
| 118 | + new \ABlocks\Blocks\EcmUpvoteCount\Block(); | |
| 119 | + new \ABlocks\Blocks\EcmUpvoteList\Block(); | |
| 120 | + new \ABlocks\Blocks\EcmClaimButton\Block(); | |
| 121 | + new \ABlocks\Blocks\EcmClaimBadge\Block(); | |
| 122 | + new \ABlocks\Blocks\EcmClaimList\Block(); | |
| 123 | + new \ABlocks\Blocks\EcmClaimCount\Block(); | |
| 124 | + } | |
| 125 | + | |
| 89 | 126 | new \ABlocks\Blocks\Container\Block(); |
| 90 | 127 | new \ABlocks\Blocks\Heading\Block(); |
| 91 | 128 | new \ABlocks\Blocks\Paragraph\Block(); |
| 129 | + new \ABlocks\Blocks\AtomicText\Block(); | |
| 130 | + new \ABlocks\Blocks\AtomicImage\Block(); | |
| 131 | + new \ABlocks\Blocks\AtomicSvg\Block(); | |
| 132 | + new \ABlocks\Blocks\AtomicDiv\Block(); | |
| 133 | + new \ABlocks\Blocks\AtomicFlex\Block(); | |
| 134 | + new \ABlocks\Blocks\AtomicGrid\Block(); | |
| 92 | 135 | new \ABlocks\Blocks\Image\Block(); |
| 93 | 136 | new \ABlocks\Blocks\Button\Block(); |
| 94 | 137 | new \ABlocks\Blocks\DualButton\Block(); |
| 95 | 138 | new \ABlocks\Blocks\Icon\Block(); |
| @@ -183,8 +226,12 @@ | ||
| 183 | 226 | public function register_block_category( $categories, $post ) { |
| 184 | 227 | return array_merge( |
| 185 | 228 | [ |
| 186 | 229 | [ |
| 230 | + 'slug' => 'ablocks-atomic', | |
| 231 | + 'title' => __( 'aBlocks Atomic', 'ablocks' ), | |
| 232 | + ], | |
| 233 | + [ | |
| 187 | 234 | 'slug' => 'ablocks', |
| 188 | 235 | 'title' => __( 'ABlocks', 'ablocks' ), |
| 189 | 236 | ], |
| 190 | 237 | [ |
| @@ -194,8 +241,12 @@ | ||
| 194 | 241 | [ |
| 195 | 242 | 'slug' => 'storeengine', |
| 196 | 243 | 'title' => __( 'StoreEngine', 'ablocks' ), |
| 197 | 244 | ], |
| 245 | + [ | |
| 246 | + 'slug' => 'easy-content-manager', | |
| 247 | + 'title' => __( 'Easy Content Manager', 'ablocks' ), | |
| 248 | + ], | |
| 198 | 249 | ], |
| 199 | 250 | $categories |
| 200 | 251 | ); |
| 201 | 252 | } |
| @@ -225,37 +276,137 @@ | ||
| 225 | 276 | return; |
| 226 | 277 | } |
| 227 | 278 | |
| 228 | 279 | $uploader = new \ABlocks\Classes\FileUpload(); |
| 229 | - if ( file_exists( $uploader->get_file_path( $post_id . '.min.css' ) ) ) { | |
| 230 | - $uploader->delete_file( $post_id . '.min.css' ); | |
| 231 | - $uploader->delete_file( $post_id . '.min.js' ); | |
| 280 | + | |
| 281 | + // Template-like content is shared across many pages, so a change there must | |
| 282 | + // invalidate every page's combined assets. Regular content only affects its | |
| 283 | + // own page — scope the invalidation to that one post so a single edit can't | |
| 284 | + // wipe the whole site's asset cache and cause a regeneration stampede. | |
| 285 | + $global_impact_post_types = apply_filters( | |
| 286 | + 'ablocks/global_asset_invalidation_post_types', | |
| 287 | + [ 'ablocks_tb', 'wp_template', 'wp_template_part', 'wp_block' ] | |
| 288 | + ); | |
| 289 | + | |
| 290 | + if ( in_array( get_post_type( $post_id ), $global_impact_post_types, true ) ) { | |
| 291 | + $this->clear_generated_block_assets(); | |
| 232 | 292 | return; |
| 233 | 293 | } |
| 234 | 294 | |
| 235 | - $this->clear_generated_block_assets(); | |
| 295 | + // Drop just this post's cached files; they regenerate on next visit. | |
| 296 | + $uploader->delete_file( $post_id . '.min.css' ); | |
| 297 | + $uploader->delete_file( $post_id . '.min.js' ); | |
| 236 | 298 | } |
| 237 | 299 | |
| 238 | 300 | public function download_google_fonts_locally( $post_id, $post, $update ) { |
| 239 | - if ( ! Helper::get_settings( 'enabled_load_google_font_locally', false ) ) { | |
| 301 | + if ( isset( $post->post_status ) && 'auto-draft' === $post->post_status ) { | |
| 240 | 302 | return; |
| 241 | 303 | } |
| 242 | 304 | |
| 243 | - if ( isset( $post->post_status ) && 'auto-draft' === $post->post_status ) { | |
| 305 | + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { | |
| 244 | 306 | return; |
| 245 | 307 | } |
| 246 | 308 | |
| 309 | + if ( false !== wp_is_post_revision( $post_id ) ) { | |
| 310 | + return; | |
| 311 | + } | |
| 312 | + | |
| 313 | + // Only process content that can contain aBlocks fonts (aBlocks blocks or | |
| 314 | + // reusable blocks that might wrap them). | |
| 315 | + if ( empty( $post->post_content ) | |
| 316 | + || ( false === strpos( $post->post_content, 'wp:ablocks' ) && false === strpos( $post->post_content, 'wp:block' ) ) ) { | |
| 317 | + return; | |
| 318 | + } | |
| 319 | + | |
| 320 | + // Collect the fonts this post actually uses from its saved attributes, | |
| 321 | + // cache them in post meta, and self-host them locally. | |
| 322 | + // See docs/FONT-MANAGEMENT-PLAN.md. | |
| 323 | + \ABlocks\Classes\FontCollector::save_post_fonts( $post_id ); | |
| 324 | + | |
| 325 | + // Templates, template parts and theme builder layouts render on pages that | |
| 326 | + // are not the queried post, so their fonts are tracked site-wide. Recompute | |
| 327 | + // (and download) here rather than on a visitor's request. | |
| 328 | + if ( in_array( get_post_type( $post_id ), \ABlocks\Classes\FontCollector::get_site_font_post_types(), true ) ) { | |
| 329 | + \ABlocks\Classes\FontCollector::update_site_fonts(); | |
| 330 | + } | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * Deleting a template/part/layout can remove the last user of a font. | |
| 335 | + * | |
| 336 | + * @param int $post_id Post being deleted. | |
| 337 | + * @param \WP_Post $post The deleted post — by this point it is gone from the | |
| 338 | + * database, so the type has to come from here. | |
| 339 | + */ | |
| 340 | + public function flush_site_fonts_on_delete( $post_id, $post = null ) { | |
| 341 | + $post_type = $post instanceof \WP_Post ? $post->post_type : get_post_type( $post_id ); | |
| 342 | + | |
| 343 | + if ( in_array( $post_type, \ABlocks\Classes\FontCollector::get_site_font_post_types(), true ) ) { | |
| 344 | + \ABlocks\Classes\FontCollector::flush_site_fonts(); | |
| 345 | + } | |
| 346 | + } | |
| 347 | + | |
| 348 | + /** | |
| 349 | + * Pre-warm a published page's combined CSS/JS in the background after save, | |
| 350 | + * via a non-blocking loopback request. This moves the parse/generate/write | |
| 351 | + * cost off the first visitor's request (PERF-2). If loopback is unavailable, | |
| 352 | + * the existing on-request generation still runs as a fallback. | |
| 353 | + */ | |
| 354 | + public function prewarm_page_assets( $post_id, $post, $update ) { | |
| 355 | + if ( ! Helper::is_enabled_assets_generation() ) { | |
| 356 | + return; | |
| 357 | + } | |
| 247 | 358 | if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { |
| 248 | 359 | return; |
| 249 | 360 | } |
| 361 | + if ( false !== wp_is_post_revision( $post_id ) ) { | |
| 362 | + return; | |
| 363 | + } | |
| 364 | + if ( ! ( $post instanceof \WP_Post ) ) { | |
| 365 | + $post = get_post( $post_id ); | |
| 366 | + } | |
| 367 | + if ( ! $post || 'publish' !== $post->post_status || ! is_post_type_viewable( $post->post_type ) ) { | |
| 368 | + return; | |
| 369 | + } | |
| 370 | + // Only for content that actually has aBlocks (or wrapping) blocks. | |
| 371 | + if ( empty( $post->post_content ) | |
| 372 | + || ( false === strpos( $post->post_content, 'wp:ablocks' ) && false === strpos( $post->post_content, 'wp:block' ) ) ) { | |
| 373 | + return; | |
| 374 | + } | |
| 375 | + if ( ! (bool) apply_filters( 'ablocks/perf/prewarm_assets', true, $post_id ) ) { | |
| 376 | + return; | |
| 377 | + } | |
| 250 | 378 | |
| 251 | - if ( false !== wp_is_post_revision( $post_id ) ) { | |
| 379 | + $url = get_permalink( $post_id ); | |
| 380 | + if ( ! $url ) { | |
| 252 | 381 | return; |
| 253 | 382 | } |
| 254 | 383 | |
| 255 | - global $ablocks_fonts; | |
| 256 | - $fontDownloader = new FontLoadLocally(); | |
| 257 | - $fontDownloader->process_font_queue( $ablocks_fonts ); | |
| 384 | + wp_remote_get( | |
| 385 | + $url, | |
| 386 | + [ | |
| 387 | + 'blocking' => false, | |
| 388 | + 'timeout' => 0.01, | |
| 389 | + 'sslverify' => false, | |
| 390 | + 'headers' => [ 'X-ABlocks-Prewarm' => '1' ], | |
| 391 | + ] | |
| 392 | + ); | |
| 393 | + } | |
| 394 | + | |
| 395 | + /** | |
| 396 | + * Recompute the global typography font set after settings are saved. | |
| 397 | + * Re-primes the in-memory settings so the collector reads fresh values. | |
| 398 | + */ | |
| 399 | + public function refresh_global_fonts() { | |
| 400 | + $GLOBALS['ablocks_settings'] = json_decode( get_option( ABLOCKS_SETTINGS_NAME, '{}' ) ); | |
| 401 | + \ABlocks\Classes\FontCollector::update_global_fonts(); | |
| 402 | + } | |
| 403 | + | |
| 404 | + /** | |
| 405 | + * Invalidate the cached global CSS variables (see Assets::global_css_variable). | |
| 406 | + */ | |
| 407 | + public function clear_global_css_cache() { | |
| 408 | + delete_transient( 'ablocks_global_css_vars' ); | |
| 258 | 409 | } |
| 259 | 410 | |
| 260 | 411 | public function form_builder_default_data(): void { |
| 261 | 412 | add_filter( |