admin_url( 'admin-ajax.php' ) ) ); // Mortgage calculator — browser-only. wp_register_script( 'mlsimport-property-calculator', $url . 'public/js/mlsimport-property-calculator.js', array(), $ver, true ); // Share / print buttons — browser-only. wp_register_script( 'mlsimport-property-share', $url . 'public/js/mlsimport-property-share.js', array(), $ver, true ); // Details-as-tabs toggling — browser-only. wp_register_script( 'mlsimport-property-tabs', $url . 'public/js/mlsimport-property-tabs.js', array(), $ver, true ); // Sticky in-page sub-nav (scrollspy + smooth scroll) — browser-only. wp_register_script( 'mlsimport-property-subnav', $url . 'public/js/mlsimport-property-subnav.js', array(), $ver, true ); // Booking sidebar tour/question tab toggle — browser-only. wp_register_script( 'mlsimport-property-booking', $url . 'public/js/mlsimport-property-booking.js', array(), $ver, true ); } /** * Enqueue the base stylesheet plus a section's declared asset handles. * * @param string[] $handles Section asset handles from the manifest. * @return void */ public static function enqueue( array $handles = array() ): void { if ( ! function_exists( 'wp_enqueue_style' ) ) { return; } self::ensure_registered(); wp_enqueue_style( self::BASE_STYLE ); foreach ( $handles as $handle ) { if ( wp_script_is( $handle, 'registered' ) ) { wp_enqueue_script( $handle ); } if ( wp_style_is( $handle, 'registered' ) ) { wp_enqueue_style( $handle ); } } } /** * Pre-enqueue the single-property page's section assets into the . * * The single templates print the header (firing wp_head) before any section * renders, so the per-section on-demand enqueue in the render dispatcher lands * too late for the head — WordPress prints those styles in the footer via * print_late_styles(), and the page paints unstyled markup that snaps into * place once the footer CSS/JS loads (issue #172, the gallery/section flash). * * Hooked on wp_enqueue_scripts, this resolves the exact sections the single * template will render — the locked hero, the "Arrange Sections" content * column and the booking sidebar — and enqueues their declared assets while * the head is still open. It reuses the same per-section asset manifests as * the on-demand path (which stays in place and no-ops for the already-queued * handles), so a section never styles itself twice and conditional vendors * (Leaflet, GLightbox) still load only when their section is active. * * @return void */ public static function enqueue_for_single(): void { if ( ! function_exists( 'is_singular' ) || ! function_exists( 'wp_enqueue_style' ) ) { return; } // Both the stored single (is_singular) and the live virtual route render // the same section stack, so cover both. $is_live = function_exists( 'get_query_var' ) && '' !== (string) get_query_var( 'mlsimport_live_listing' ); if ( ! $is_live && ! is_singular( 'mlsimport_property' ) ) { return; } if ( function_exists( 'mlsimport_register_builtin_property_sections' ) ) { mlsimport_register_builtin_property_sections(); } if ( ! function_exists( 'mlsimport_property_section_registry' ) ) { return; } $id = $is_live ? 0 : (int) get_queried_object_id(); $active = function_exists( 'mlsimport_standalone_active_sections' ) ? mlsimport_standalone_active_sections() : array(); /** This filter is documented in templates/single-mlsimport-property.php */ $active = (array) apply_filters( 'mlsimport_single_property_sections', $active, $id ); // The locked hero + content column + booking sidebar — the full set the // single template renders. $slugs = array_merge( array( 'breadcrumbs', 'property_gallery', 'title_bar', 'subnav' ), $active, array( 'booking' ) ); $registry = mlsimport_property_section_registry(); $handles = array(); foreach ( array_unique( $slugs ) as $slug ) { if ( isset( $registry[ $slug ]['assets'] ) ) { $handles = array_merge( $handles, (array) $registry[ $slug ]['assets'] ); } } self::enqueue( array_unique( $handles ) ); } }