| 1 |
<?php |
| 2 |
/** |
| 3 |
* Standalone (theme_id 990) single-property section assets. |
| 4 |
* |
| 5 |
* Registers the front-end CSS/JS each section can use and enqueues them |
| 6 |
* on demand: the dispatcher calls enqueue() with a section's declared asset |
| 7 |
* handles only when that section actually renders, so Splide/Leaflet/etc. load |
| 8 |
* only on pages that use them (decision 6/8). Handles are registered idempotently |
| 9 |
* so enqueue works regardless of hook order. See docs/adr/0005. |
| 10 |
* |
| 11 |
* @package Mlsimport |
| 12 |
*/ |
| 13 |
|
| 14 |
if ( ! defined( 'ABSPATH' ) ) { |
| 15 |
exit; |
| 16 |
} |
| 17 |
|
| 18 |
/** |
| 19 |
* Registers and on-demand enqueues single-property section assets. |
| 20 |
*/ |
| 21 |
class Mlsimport_Property_Section_Assets { |
| 22 |
|
| 23 |
/** |
| 24 |
* The base stylesheet handle, enqueued whenever any section renders. |
| 25 |
*/ |
| 26 |
const BASE_STYLE = 'mlsimport-property-sections'; |
| 27 |
|
| 28 |
/** |
| 29 |
* Register all section asset handles once. Idempotent. |
| 30 |
* |
| 31 |
* @return void |
| 32 |
*/ |
| 33 |
public static function ensure_registered(): void { |
| 34 |
static $done = false; |
| 35 |
if ( $done || ! function_exists( 'wp_register_style' ) ) { |
| 36 |
return; |
| 37 |
} |
| 38 |
$done = true; |
| 39 |
|
| 40 |
$url = defined( 'MLSIMPORT_PLUGIN_URL' ) ? MLSIMPORT_PLUGIN_URL : ''; |
| 41 |
$ver = defined( 'MLSIMPORT_VERSION' ) ? MLSIMPORT_VERSION : false; |
| 42 |
|
| 43 |
wp_register_style( self::BASE_STYLE, $url . 'public/css/mlsimport-property-sections.css', array(), $ver ); |
| 44 |
// Re-theme the section tokens from the "Main Color" design setting on EVERY |
| 45 |
// page that loads the base style — property pages, page blocks, the agent |
| 46 |
// profile (enqueued directly in agent-sections.php) and the editor preview. |
| 47 |
// Attached at REGISTRATION so all enqueue paths get it, not just enqueue(). |
| 48 |
if ( function_exists( 'mlsimport_standalone_attach_brand_color' ) ) { |
| 49 |
mlsimport_standalone_attach_brand_color( self::BASE_STYLE ); |
| 50 |
} |
| 51 |
|
| 52 |
// Single-agent profile styles — layered on the base tokens/section shell. |
| 53 |
wp_register_style( 'mlsimport-agent', $url . 'public/css/mlsimport-agent.css', array( self::BASE_STYLE ), $ver ); |
| 54 |
|
| 55 |
// Vendored Splide (gallery/sliders) — registered, enqueued only on demand. |
| 56 |
wp_register_style( 'mlsimport-splide', $url . 'public/vendor/splide/splide.min.css', array(), $ver ); |
| 57 |
wp_register_script( 'mlsimport-splide', $url . 'public/vendor/splide/splide.min.js', array(), $ver, true ); |
| 58 |
wp_register_script( 'mlsimport-property-slider', $url . 'public/js/mlsimport-property-slider.js', array( 'mlsimport-splide' ), $ver, true ); |
| 59 |
|
| 60 |
// Vendored GLightbox (gallery/slider click-to-zoom) — registered, enqueued on demand. |
| 61 |
wp_register_style( 'mlsimport-glightbox', $url . 'public/vendor/glightbox/glightbox.min.css', array(), $ver ); |
| 62 |
wp_register_script( 'mlsimport-glightbox', $url . 'public/vendor/glightbox/glightbox.min.js', array(), $ver, true ); |
| 63 |
wp_register_script( 'mlsimport-property-lightbox', $url . 'public/js/mlsimport-property-lightbox.js', array( 'mlsimport-glightbox' ), $ver, true ); |
| 64 |
|
| 65 |
// Vendored Leaflet + map init (map section) — registered, enqueued on demand. |
| 66 |
wp_register_style( 'mlsimport-leaflet', $url . 'public/vendor/leaflet/leaflet.css', array(), $ver ); |
| 67 |
wp_register_script( 'mlsimport-leaflet', $url . 'public/vendor/leaflet/leaflet.js', array(), $ver, true ); |
| 68 |
wp_register_script( 'mlsimport-property-map', $url . 'public/js/mlsimport-property-map.js', array(), $ver, true ); |
| 69 |
|
| 70 |
// Multi-marker map for the "Map with Listings" page block — reuses Leaflet. |
| 71 |
wp_register_script( 'mlsimport-page-block-map', $url . 'public/js/mlsimport-page-block-map.js', array(), $ver, true ); |
| 72 |
|
| 73 |
// Half Map page block: split listings/map surface. The coordinator depends on |
| 74 |
// the page-block map script (which exposes node.mlsimportMap on query maps). |
| 75 |
wp_register_style( 'mlsimport-half-map', $url . 'public/css/mlsimport-half-map.css', array(), $ver ); |
| 76 |
wp_register_script( 'mlsimport-half-map', $url . 'public/js/mlsimport-half-map.js', array( 'mlsimport-page-block-map' ), $ver, true ); |
| 77 |
|
| 78 |
// The "I'm interested in" dropdown widget. Declared as a dependency of the lead |
| 79 |
// script rather than as a section asset, so it loads exactly where lead forms |
| 80 |
// load — including the booking rail's Ask a Question panel — with no section |
| 81 |
// declaration to keep in sync. |
| 82 |
wp_register_script( 'mlsimport-property-interest', $url . 'public/js/mlsimport-property-interest.js', array(), $ver, true ); |
| 83 |
|
| 84 |
// Lead forms — AJAX submit; localize the admin-ajax URL. |
| 85 |
wp_register_script( 'mlsimport-property-lead', $url . 'public/js/mlsimport-property-lead.js', array( 'mlsimport-property-interest' ), $ver, true ); |
| 86 |
wp_localize_script( |
| 87 |
'mlsimport-property-lead', |
| 88 |
'MLSImportLead', |
| 89 |
array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) |
| 90 |
); |
| 91 |
|
| 92 |
// Mortgage calculator — browser-only. |
| 93 |
wp_register_script( 'mlsimport-property-calculator', $url . 'public/js/mlsimport-property-calculator.js', array(), $ver, true ); |
| 94 |
|
| 95 |
// Share / print buttons — browser-only. |
| 96 |
wp_register_script( 'mlsimport-property-share', $url . 'public/js/mlsimport-property-share.js', array(), $ver, true ); |
| 97 |
|
| 98 |
// Details-as-tabs toggling — browser-only. |
| 99 |
wp_register_script( 'mlsimport-property-tabs', $url . 'public/js/mlsimport-property-tabs.js', array(), $ver, true ); |
| 100 |
|
| 101 |
// Sticky in-page sub-nav (scrollspy + smooth scroll) — browser-only. |
| 102 |
wp_register_script( 'mlsimport-property-subnav', $url . 'public/js/mlsimport-property-subnav.js', array(), $ver, true ); |
| 103 |
|
| 104 |
// Booking sidebar tour/question tab toggle — browser-only. |
| 105 |
wp_register_script( 'mlsimport-property-booking', $url . 'public/js/mlsimport-property-booking.js', array(), $ver, true ); |
| 106 |
} |
| 107 |
|
| 108 |
/** |
| 109 |
* Enqueue the base stylesheet plus a section's declared asset handles. |
| 110 |
* |
| 111 |
* @param string[] $handles Section asset handles from the manifest. |
| 112 |
* @return void |
| 113 |
*/ |
| 114 |
public static function enqueue( array $handles = array() ): void { |
| 115 |
if ( ! function_exists( 'wp_enqueue_style' ) ) { |
| 116 |
return; |
| 117 |
} |
| 118 |
self::ensure_registered(); |
| 119 |
|
| 120 |
wp_enqueue_style( self::BASE_STYLE ); |
| 121 |
|
| 122 |
foreach ( $handles as $handle ) { |
| 123 |
if ( wp_script_is( $handle, 'registered' ) ) { |
| 124 |
wp_enqueue_script( $handle ); |
| 125 |
} |
| 126 |
if ( wp_style_is( $handle, 'registered' ) ) { |
| 127 |
wp_enqueue_style( $handle ); |
| 128 |
} |
| 129 |
} |
| 130 |
} |
| 131 |
|
| 132 |
/** |
| 133 |
* Pre-enqueue the single-property page's section assets into the <head>. |
| 134 |
* |
| 135 |
* The single templates print the header (firing wp_head) before any section |
| 136 |
* renders, so the per-section on-demand enqueue in the render dispatcher lands |
| 137 |
* too late for the head — WordPress prints those styles in the footer via |
| 138 |
* print_late_styles(), and the page paints unstyled markup that snaps into |
| 139 |
* place once the footer CSS/JS loads (issue #172, the gallery/section flash). |
| 140 |
* |
| 141 |
* Hooked on wp_enqueue_scripts, this resolves the exact sections the single |
| 142 |
* template will render — the locked hero, the "Arrange Sections" content |
| 143 |
* column and the booking sidebar — and enqueues their declared assets while |
| 144 |
* the head is still open. It reuses the same per-section asset manifests as |
| 145 |
* the on-demand path (which stays in place and no-ops for the already-queued |
| 146 |
* handles), so a section never styles itself twice and conditional vendors |
| 147 |
* (Leaflet, GLightbox) still load only when their section is active. |
| 148 |
* |
| 149 |
* @return void |
| 150 |
*/ |
| 151 |
public static function enqueue_for_single(): void { |
| 152 |
if ( ! function_exists( 'is_singular' ) || ! function_exists( 'wp_enqueue_style' ) ) { |
| 153 |
return; |
| 154 |
} |
| 155 |
|
| 156 |
// Both the stored single (is_singular) and the live virtual route render |
| 157 |
// the same section stack, so cover both. |
| 158 |
$is_live = function_exists( 'get_query_var' ) && '' !== (string) get_query_var( 'mlsimport_live_listing' ); |
| 159 |
if ( ! $is_live && ! is_singular( 'mlsimport_property' ) ) { |
| 160 |
return; |
| 161 |
} |
| 162 |
|
| 163 |
if ( function_exists( 'mlsimport_register_builtin_property_sections' ) ) { |
| 164 |
mlsimport_register_builtin_property_sections(); |
| 165 |
} |
| 166 |
if ( ! function_exists( 'mlsimport_property_section_registry' ) ) { |
| 167 |
return; |
| 168 |
} |
| 169 |
|
| 170 |
$id = $is_live ? 0 : (int) get_queried_object_id(); |
| 171 |
$active = function_exists( 'mlsimport_standalone_active_sections' ) |
| 172 |
? mlsimport_standalone_active_sections() |
| 173 |
: array(); |
| 174 |
/** This filter is documented in templates/single-mlsimport-property.php */ |
| 175 |
$active = (array) apply_filters( 'mlsimport_single_property_sections', $active, $id ); |
| 176 |
|
| 177 |
// The locked hero + content column + booking sidebar — the full set the |
| 178 |
// single template renders. |
| 179 |
$slugs = array_merge( array( 'breadcrumbs', 'property_gallery', 'title_bar', 'subnav' ), $active, array( 'booking' ) ); |
| 180 |
$registry = mlsimport_property_section_registry(); |
| 181 |
$handles = array(); |
| 182 |
foreach ( array_unique( $slugs ) as $slug ) { |
| 183 |
if ( isset( $registry[ $slug ]['assets'] ) ) { |
| 184 |
$handles = array_merge( $handles, (array) $registry[ $slug ]['assets'] ); |
| 185 |
} |
| 186 |
} |
| 187 |
|
| 188 |
self::enqueue( array_unique( $handles ) ); |
| 189 |
} |
| 190 |
} |
| 191 |
|