PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 7.1.1
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v7.1.1
7.2.1 7.2 7.1.2 7.1.1 7.1 7.0.4 7.0.6 7.0.7 6.3.8 6.3.7 6.3.6 6.3.5 6.3.4 6.3.3 6.3.1 trunk 5.7.3 5.7.5 5.8.1 5.8.2 5.8.3 5.8.4 5.8.6 6.0.4 6.0.5 All 36 releases
mlsimport / includes / standalone / property-section-registry.php

property-section-registry.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 7.1.1, at includes/standalone/property-section-registry.php

205 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Standalone (theme_id 990) single-property section manifest + dispatcher.
4 *
5 * One registry maps a section slug to its metadata (label, render callback,
6 * accepted args, required front-end assets). Every page-builder adapter
7 * (Shortcode, Gutenberg, Elementor, future builders) loops this manifest, so
8 * adding a section is one register call + one render fn and all builders pick
9 * it up. The dispatcher is the single place that resolves the render fn,
10 * resolves the property and (later) enqueues the section's assets. See
11 * docs/adr/0005.
12 *
13 * @package Mlsimport
14 */
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 require_once __DIR__ . '/property-sections.php';
21 require_once __DIR__ . '/class-mlsimport-property-section-assets.php';
22 require_once __DIR__ . '/class-mlsimport-property-lead.php';
23
24 /**
25 * Register a single-property section in the manifest.
26 *
27 * @param string $slug Section slug (e.g. 'price').
28 * @param array $def {
29 * @type string $label Editor-facing label.
30 * @type callable $render Render fn: ( int $id, array $args ) => string.
31 * @type array $args Optional accepted arg keys (behavioral).
32 * @type array $assets Optional asset handles to enqueue when rendered.
33 * }
34 * @return void
35 */
36 function mlsimport_register_property_section( string $slug, array $def ): void {
37 $registry =& mlsimport_property_section_registry();
38
39 $registry[ $slug ] = array(
40 'label' => isset( $def['label'] ) ? (string) $def['label'] : $slug,
41 'render' => isset( $def['render'] ) ? $def['render'] : '',
42 'args' => isset( $def['args'] ) ? (array) $def['args'] : array(),
43 'assets' => isset( $def['assets'] ) ? (array) $def['assets'] : array(),
44 );
45 }
46
47 /**
48 * The registered sections, slug => definition.
49 *
50 * @return array
51 */
52 function mlsimport_get_property_sections(): array {
53 /** Filter the section manifest: add/remove/reorder sections globally. @since 6.3 */
54 return (array) apply_filters( 'mlsimport_property_sections', mlsimport_property_section_registry() );
55 }
56
57 /**
58 * Render a registered section by slug (the one dispatch point for all builders).
59 *
60 * @param string $slug Section slug.
61 * @param int $id Property post ID (0 = current loop post).
62 * @param array $args Behavioral args.
63 * @return string HTML, or '' for an unknown slug / uncallable render fn.
64 */
65 function mlsimport_render_property_section( string $slug, int $id = 0, array $args = array() ): string {
66 $registry = mlsimport_property_section_registry();
67 if ( ! isset( $registry[ $slug ] ) || ! is_callable( $registry[ $slug ]['render'] ) ) {
68 return '';
69 }
70
71 // Manifest args are per-section defaults (e.g. a slider variant); caller args win.
72 $args = array_merge( $registry[ $slug ]['args'], $args );
73 /** Filter the resolved section args before render. @since 6.3 */
74 $args = (array) apply_filters( 'mlsimport_section_args', $args, $slug, $id );
75
76 // Action slot before the section. Echoed output is buffered so the
77 // function still returns one complete string (the return-string contract).
78 ob_start();
79 /** Inject markup before any section; $slug identifies which. @since 6.3 */
80 do_action( 'mlsimport_before_section', $slug, $id, $args );
81 /** Inject markup before a section. Dynamic by slug. @since 6.3 */
82 do_action( "mlsimport_before_section_{$slug}", $id, $args );
83 $before = (string) ob_get_clean();
84
85 $html = (string) call_user_func( $registry[ $slug ]['render'], $id, $args );
86
87 // Data-driven: a section's assets load only when it actually renders output.
88 // Gated on the rendered markup, before filters/action slots transform it.
89 if ( '' !== $html ) {
90 Mlsimport_Property_Section_Assets::enqueue( $registry[ $slug ]['assets'] );
91 }
92
93 /** Filter a single section's markup. Dynamic by slug. @since 6.3 */
94 $html = apply_filters( "mlsimport_section_{$slug}_html", $html, $id, $args );
95 /** Filter any section's markup; $slug identifies which. @since 6.3 */
96 $html = apply_filters( 'mlsimport_section_html', $html, $slug, $id, $args );
97
98 // Action slot after the section, buffered to preserve the return contract.
99 ob_start();
100 /** Inject markup after a section. Dynamic by slug. @since 6.3 */
101 do_action( "mlsimport_after_section_{$slug}", $id, $args );
102 /** Inject markup after any section; $slug identifies which. @since 6.3 */
103 do_action( 'mlsimport_after_section', $slug, $id, $args );
104 $after = (string) ob_get_clean();
105
106 return $before . $html . $after;
107 }
108
109 /**
110 * Register the plugin's built-in sections. Idempotent.
111 *
112 * @return void
113 */
114 function mlsimport_register_builtin_property_sections(): void {
115 static $done = false;
116 if ( $done ) {
117 return;
118 }
119 $done = true;
120
121 // slug => [ label, render fn, default args, asset handles ].
122 $lightbox = array( 'mlsimport-glightbox', 'mlsimport-property-lightbox' );
123 $slider = array_merge( array( 'mlsimport-splide', 'mlsimport-property-slider' ), $lightbox );
124 $lead = array( 'mlsimport-property-lead' );
125 $sections = array(
126 'price' => array( __( 'Property Price', 'mlsimport' ), 'mlsimport_property_price' ),
127 'price_info' => array( __( 'Additional Price Info', 'mlsimport' ), 'mlsimport_property_price_info' ),
128 'title' => array( __( 'Property Title', 'mlsimport' ), 'mlsimport_property_title' ),
129 'title_bar' => array( __( 'Title Bar (price + actions)', 'mlsimport' ), 'mlsimport_property_title_bar', array(), array( 'mlsimport-property-share' ) ),
130 'status' => array( __( 'Property Status', 'mlsimport' ), 'mlsimport_property_status' ),
131 'address' => array( __( 'Property Address', 'mlsimport' ), 'mlsimport_property_address' ),
132 'header' => array( __( 'Header Section', 'mlsimport' ), 'mlsimport_property_header' ),
133 'subnav' => array( __( 'Section Navigation', 'mlsimport' ), 'mlsimport_property_subnav', array(), array( 'mlsimport-property-subnav' ) ),
134 'breadcrumbs' => array( __( 'Breadcrumbs', 'mlsimport' ), 'mlsimport_property_breadcrumbs' ),
135 'overview' => array( __( 'Overview', 'mlsimport' ), 'mlsimport_property_overview' ),
136 'features' => array( __( 'Features', 'mlsimport' ), 'mlsimport_property_features' ),
137
138 // Containers — each renders an ordered list of ANY registered sections.
139 'tabs' => array( __( 'Sections as Tabs', 'mlsimport' ), 'mlsimport_property_tabs', array(), array( 'mlsimport-property-tabs' ) ),
140 'accordion' => array( __( 'Sections as Accordion', 'mlsimport' ), 'mlsimport_property_accordion' ),
141 'description' => array( __( 'Description', 'mlsimport' ), 'mlsimport_property_description' ),
142 'content' => array( __( 'Content', 'mlsimport' ), 'mlsimport_property_content' ),
143 'excerpt' => array( __( 'Excerpt', 'mlsimport' ), 'mlsimport_property_excerpt' ),
144
145 // Media — one render fn, layout/variant baked per slug.
146 'property_gallery' => array( __( 'Property Gallery', 'mlsimport' ), 'mlsimport_property_media', array(), $slider ),
147 'featured_image' => array( __( 'Featured Image', 'mlsimport' ), 'mlsimport_property_featured_image' ),
148 'gallery' => array( __( 'Gallery', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'grid' ), $lightbox ),
149 'gallery_masonry' => array( __( 'Masonry Gallery v1', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'masonry' ), $lightbox ),
150 'gallery_masonry_v2' => array( __( 'Masonry Gallery v2', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'masonry_v2' ), $lightbox ),
151 'slider_classic' => array( __( 'Classic Slider', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'slider', 'variant' => 'classic' ), $slider ),
152 'slider_vertical' => array( __( 'Vertical Slider', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'slider', 'variant' => 'vertical' ), $slider ),
153 'slider_multi' => array( __( 'Multi Image Slider', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'slider', 'variant' => 'multi' ), $slider ),
154 'slider_full' => array( __( 'Full Width Slider', 'mlsimport' ), 'mlsimport_property_gallery', array( 'layout' => 'slider', 'variant' => 'full' ), $slider ),
155
156 // Location (manages its own provider-specific assets).
157 'map' => array( __( 'Map', 'mlsimport' ), 'mlsimport_property_map' ),
158
159 // Agent / contact / lead capture.
160 'agent_card' => array( __( 'Agent Card', 'mlsimport' ), 'mlsimport_property_agent_card' ),
161 'mobile_agent_bar' => array( __( 'Mobile Agent Bar (sticky)', 'mlsimport' ), 'mlsimport_property_mobile_agent_bar' ),
162 'agent_contact' => array( __( 'Agent Contact Form', 'mlsimport' ), 'mlsimport_property_lead_form', array( 'variant' => 'contact' ), $lead ),
163 'agent_form' => array( __( 'Agent Form Section', 'mlsimport' ), 'mlsimport_property_lead_form', array( 'variant' => 'form' ), $lead ),
164 'agent_form_sidebar' => array( __( 'Agent Form (sidebar)', 'mlsimport' ), 'mlsimport_property_lead_form', array( 'variant' => 'sidebar' ), $lead ),
165 'schedule_tour' => array( __( 'Schedule a Tour', 'mlsimport' ), 'mlsimport_property_lead_form', array( 'variant' => 'tour' ), $lead ),
166 'booking' => array( __( 'Booking Sidebar', 'mlsimport' ), 'mlsimport_property_booking', array(), array( 'mlsimport-property-lead', 'mlsimport-property-booking' ) ),
167 'calculator' => array( __( 'Mortgage Calculator', 'mlsimport' ), 'mlsimport_property_calculator', array(), array( 'mlsimport-property-calculator' ) ),
168
169 // Engagement / media.
170 'virtual_tour' => array( __( 'Virtual Tour', 'mlsimport' ), 'mlsimport_property_embed', array( 'source' => 'virtual_tour' ) ),
171 'video' => array( __( 'Video', 'mlsimport' ), 'mlsimport_property_embed', array( 'source' => 'video' ) ),
172 'share' => array( __( 'Share / Print', 'mlsimport' ), 'mlsimport_property_share', array(), array( 'mlsimport-property-share' ) ),
173 'attribution' => array( __( 'MLS Attribution', 'mlsimport' ), 'mlsimport_property_attribution' ),
174 'similar' => array( __( 'Similar Listings', 'mlsimport' ), 'mlsimport_property_similar' ),
175 );
176
177 // The nine field sections. One render fn, the slug baked in per section — the
178 // same variant pattern the galleries use.
179 foreach ( mlsimport_property_field_section_titles() as $slug => $title ) {
180 $sections[ $slug ] = array( $title, 'mlsimport_property_field_section', array( 'section' => $slug ) );
181 }
182
183 foreach ( $sections as $slug => $def ) {
184 mlsimport_register_property_section(
185 $slug,
186 array(
187 'label' => $def[0],
188 'render' => $def[1],
189 'args' => isset( $def[2] ) ? $def[2] : array(),
190 'assets' => isset( $def[3] ) ? $def[3] : array(),
191 )
192 );
193 }
194 }
195
196 /**
197 * Internal: the by-reference registry store.
198 *
199 * @return array
200 */
201 function &mlsimport_property_section_registry(): array {
202 static $registry = array();
203 return $registry;
204 }
205