PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / trunk
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings vtrunk
7.2.2 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 All 37 releases
mlsimport / includes / standalone / listing-card.php

listing-card.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings trunk, at includes/standalone/listing-card.php

123 lines 6.0 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) listing-card view model + hook surface.
4 *
5 * Every property grid renders through Mlsimport_Standalone_Render::render_cards(),
6 * which picks the card template (v1/v2/v3) via mlsimport_standalone_card_template().
7 * Each card template builds its data once from this one helper, so the three
8 * designs stay consistent and a new card design is a thin template, not a new data
9 * pass. The card action slots below are the WooCommerce-style extension points
10 * fired inside every card template.
11 *
12 * Card action slots (each fired with ( WP_Post $post, object|null $row )):
13 * action mlsimport_card_before — just after <article> opens (ribbons)
14 * action mlsimport_card_badges — inside the badge row over the photo, after the
15 * status badge. The plugin's own "Featured" flag
16 * hooks here (mlsimport_card_featured_flag(), 10).
17 * action mlsimport_card_after_media — direct child of <article>, after the media/link
18 * (favorite heart, gallery count); positioned over
19 * the photo via CSS, so it sits OUTSIDE the card's
20 * <a> link and fires on thumbnail-less cards too
21 * action mlsimport_card_body_start — top of the card body
22 * action mlsimport_card_body_end — bottom of the card body (CTA buttons)
23 * action mlsimport_card_after — just before </article> closes
24 * Filter:
25 * filter mlsimport_card_view ( array $view, WP_Post $post, object|null $row )
26 *
27 * @package Mlsimport
28 */
29
30 if ( ! defined( 'ABSPATH' ) ) {
31 exit;
32 }
33
34 /**
35 * Build one listing card's view model from the post + its listings row. Pulls the
36 * clean RESO address, formatted price, spec line, status and agency, so the card
37 * templates only lay out — they don't re-derive.
38 *
39 * @param WP_Post $post The listing post.
40 * @param object|null $row The mlsimport_listings row (searchable scalars).
41 * @return array
42 */
43 function mlsimport_card_view( $post, $row ): array {
44 // Cast the post ID once for the meta/permalink/thumbnail lookups below.
45 $pid = (int) $post->ID;
46
47 // Address: the clean RESO UnparsedAddress is the heading; the raw post title
48 // (often an importer concatenation) is only the fallback.
49 $address = trim( (string) get_post_meta( $pid, 'mlsimport_UnparsedAddress', true ) );
50 if ( '' === $address ) {
51 $address = get_the_title( $pid );
52 }
53
54 // Price: keep null when the row has none; otherwise format as "$ 1,234,567".
55 $price = ( isset( $row->price ) && null !== $row->price && '' !== $row->price ) ? (float) $row->price : null;
56 $price_fmt = null !== $price ? '$ ' . number_format( $price ) : '';
57
58 // Spec line: only the parts present.
59 $specs = array();
60 // Beds — pluralized; drop the decimal for whole numbers.
61 if ( isset( $row->bedrooms ) && null !== $row->bedrooms && '' !== $row->bedrooms ) {
62 $b = (float) $row->bedrooms;
63 $specs[] = sprintf( _n( '%s bed', '%s beds', (int) ceil( $b ), 'mlsimport' ), number_format_i18n( $b, ( $b === (float) (int) $b ) ? 0 : 1 ) );
64 }
65 // Baths — pluralized; drop the decimal for whole numbers.
66 if ( isset( $row->bathrooms ) && null !== $row->bathrooms && '' !== $row->bathrooms ) {
67 $ba = (float) $row->bathrooms;
68 $specs[] = sprintf( _n( '%s bath', '%s baths', (int) ceil( $ba ), 'mlsimport' ), number_format_i18n( $ba, ( $ba === (float) (int) $ba ) ? 0 : 1 ) );
69 }
70 // Living area — formatted number plus the ft² unit.
71 if ( isset( $row->living_area ) && null !== $row->living_area && '' !== $row->living_area ) {
72 $specs[] = number_format_i18n( (float) $row->living_area ) . ' ' . __( 'ft²', 'mlsimport' );
73 }
74
75 // Assemble the view model the card templates lay out (no further deriving).
76 $view = array(
77 'id' => $pid,
78 'permalink' => (string) get_permalink( $pid ),
79 'address' => $address,
80 'price' => $price,
81 'price_fmt' => $price_fmt,
82 'status' => isset( $row->status ) ? trim( (string) $row->status ) : '',
83 'specs' => $specs,
84 'office' => trim( (string) get_post_meta( $pid, 'mlsimport_ListOfficeName', true ) ),
85 'logo' => function_exists( 'mlsimport_standalone_mls_logo_url' ) ? mlsimport_standalone_mls_logo_url() : '',
86 'has_thumb' => has_post_thumbnail( $pid ),
87 // Photo URL for the card media — rendered as a CSS background-image (never an
88 // <img>), the same convention as the map/featured cards.
89 'thumb' => has_post_thumbnail( $pid ) ? (string) get_the_post_thumbnail_url( $pid, 'large' ) : '',
90 );
91
92 /** Filter one card's view model before the template lays it out. @since 6.4 */
93 return (array) apply_filters( 'mlsimport_card_view', $view, $post, $row );
94 }
95
96 /**
97 * Print the "Featured" flag on a featured listing's card (issue #288).
98 *
99 * Hooked on mlsimport_card_badges, which all three card templates fire in the
100 * badge row over the photo, so the flag sits inline after the status badge. The flag is read from the listings row ($row->featured, copied
101 * from the "Featured listing" checkbox by Mlsimport_Standalone_Row::upsert()),
102 * which costs no extra query. A card with no row (live passthrough mode) or an
103 * unfeatured listing prints nothing.
104 *
105 * @param WP_Post $post The property post.
106 * @param object|null $row The mlsimport_listings row, or null.
107 * @return void
108 */
109 function mlsimport_card_featured_flag( $post, $row ): void {
110 // Step 1: only a featured listing gets the flag.
111 if ( empty( $row->featured ) ) {
112 return;
113 }
114
115 // Step 2: same look as the Featured Property block's flag, plus a card-specific
116 // class that styles it like the status badge beside it (mlsimport-listings.css).
117 $html = '<span class="mlsimport-featured__flag mlsimport-listing-card__featured">' . esc_html__( 'Featured', 'mlsimport' ) . '</span>';
118
119 /** Filter the card's "Featured" flag markup ('' hides it). @since 7.2.2 */
120 echo wp_kses_post( (string) apply_filters( 'mlsimport_card_featured_flag', $html, $post, $row ) );
121 }
122 add_action( 'mlsimport_card_badges', 'mlsimport_card_featured_flag', 10, 2 );
123