=== Core Listing ===
Contributors: corelisting
Tags: real estate, commercial real estate, listings, cre, crm
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.4.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Embed live commercial real estate listings, sold deals and your team roster from your Core Listing account using a shortcode or block.

== Description ==

Core Listing is a commercial real estate listing and CRM platform for brokerages. This plugin connects your WordPress site to your Core Listing account so the inventory you already maintain there appears on your own website, and stays current without anyone re-keying it.

Add a shortcode or a block to any page and the plugin renders a responsive grid of listing cards built from live data. Each card links through to the full listing page on your Core Listing portal.

You decide what those cards say. In Core Listing, under Account Settings and then Listing Display, you choose the heading, the line beneath it and the detail rows: price, custom price text, square footage, units, beds, cap rate, occupancy, year built, class, parking, any account custom field, and more. Every label is renamable. You also choose where those details sit: below the photo, or beside it for a card that carries more rows. That arrangement is one setting for your whole brokerage, so every grid you publish is built the same way. The fields are not: because a hotel and a retail strip rarely want the same three numbers, you can set a different field list for each property type, and override a single listing outright when it needs its own. The plugin renders whatever you chose, so your website, your Core Listing portal and your sold page always agree.

= What you can embed =

* **Active inventory** with `[corelisting_listings]`. Filter by office, property type, status and price range; control sort order, result limit and column count.
* **Sold and closed transactions** with `[corelisting_sold]`, for a "Recent Closings" or track record page. Accepts the same filters, with status locked to sold.
* **Your public team roster** with `[corelisting_members]`, showing the photo, name, titles, licenses, biography, email and phone for every member flagged "Show on Team Page" in Core Listing. Scope it to a single office, or hide biographies with `show_bio="no"`.

Every shortcode is also registered as a block, so you can insert and configure it visually in the editor with a live preview and no shortcode syntax to remember.

= Built to stay in sync =

Listings are cached locally as WordPress transients, so a typical page view never makes an outbound request. When you change a listing in Core Listing, a signed webhook clears that cache within seconds, so your site is fast and current at the same time. Incoming webhooks are verified with an HMAC-SHA256 signature and rejected if the signature does not match.

If your brokerage has a verified white label domain on file, listing links automatically use it, so visitors stay on your own branded host.

= Styling =

Output is plain, semantic HTML with stable CSS class names such as `.corelisting-grid`, `.corelisting-card`, `.corelisting-photo` and `.corelisting-detail-value`. Every detail row also carries a class naming its field, for example `.corelisting-detail-price`, so a single row can be styled on its own. Restyle everything from Appearance to Customize to Additional CSS without touching plugin files.

= External services =

This plugin is a client for Core Listing, a third party software as a service platform at [corelisting.com](https://corelisting.com). It is only useful with an active Core Listing account, and it makes no outbound request at all until you save an API key on the settings screen.

Once connected, the plugin contacts `https://corelisting.com` (or your account's own white label domain, if you have configured one) in the following situations:

* **Rendering a shortcode or block, when the local cache is cold.** The plugin requests your listings, sold listings or team roster. It sends your API key for authentication and nothing else. No visitor information is included.
* **Clicking "Test Connection".** The plugin requests your account name and white label domain to confirm the API key works.
* **Once a day in the background.** The plugin re-checks your account's white label domain so listing links stay correct.
* **Clicking "Register Webhook with Core Listing".** The plugin sends this site's address, the plugin version and the REST webhook URL on this site, so Core Listing knows where to deliver listing change events. This is the only action that transmits your site address, and it only happens when you click the button.
* **Deleting the plugin.** The plugin tells Core Listing to release the webhook registration for this site, so events are no longer dispatched to a site that removed the integration. This is skipped entirely if no API key was ever saved.

No visitor, customer or personally identifiable data from your WordPress site is ever transmitted, and the plugin sets no cookies and performs no tracking.

Service terms: [corelisting.com/terms](https://corelisting.com/terms). Privacy policy: [corelisting.com/privacy-policy](https://corelisting.com/privacy-policy).

== Installation ==

1. Install the plugin through Plugins to Add New in your WordPress admin, or upload the plugin zip through Plugins to Add New to Upload Plugin.
2. Activate **Core Listing**.
3. In Core Listing, go to Integrations to WordPress and click **Generate WordPress API Key**, then copy the key.
4. In WordPress, go to **Settings to Core Listing**. Enter your Core Listing URL and paste the API key, then save.
5. Click **Test Connection** to confirm the key works, then **Register Webhook with Core Listing** so listing changes sync automatically.
6. Add `[corelisting_listings]` to any page, or insert the "Core Listing Listings" block.

For the Core Listing URL, use your confirmed white label domain (for example `https://listings.yourbrokerage.com`) so images are served from your own host. If you do not have one yet, use `https://corelisting.com`. Your subdomain on its own, such as `acme`, also works as shorthand for `https://acme.corelisting.com`.

== Frequently Asked Questions ==

= Do I need a Core Listing account? =

Yes. This plugin is a display client for the Core Listing platform and has no listing data of its own. Without an account and an API key it has nothing to show.

= Where do I get the API key? =

In Core Listing, go to Integrations to WordPress and click "Generate WordPress API Key". The key is scoped so it can only read the data this plugin needs. You can revoke it from the same screen at any time.

= What shortcodes are available? =

`[corelisting_listings]` for active inventory, `[corelisting_sold]` for sold and closed transactions, and `[corelisting_members]` for your public team roster. Each accepts attributes such as `columns`, `limit`, `sort` and `office`, all documented on the Settings to Core Listing screen.

= I am upgrading from 1.3.1 and my listings disappeared. What happened? =

The shortcodes were renamed in 1.4.0, from `[crm_listings]`, `[crm_sold]` and `[crm_members]` to `[corelisting_listings]`, `[corelisting_sold]` and `[corelisting_members]`. Edit any page still using an old name and change it. Pages built with the blocks rather than the shortcodes are unaffected.

= Can I show listings from just one office? =

Yes. Pass the `office` attribute with either the office name or its numeric ID, for example `[corelisting_listings office="Denver"]`. It works on all three shortcodes.

= How quickly do changes in Core Listing appear on my site? =

Within seconds, once you have clicked "Register Webhook with Core Listing". Core Listing then pushes a signed event on every listing change and the plugin clears its cache immediately. Without the webhook, changes appear when the cache expires, which defaults to 15 minutes and is configurable.

= Can I change which fields each card shows? =

Yes, in Core Listing rather than in WordPress. Go to Account Settings and then Listing Display, pick the heading, the sub-line and the detail rows, and rename any label. The same screen has one brokerage-wide choice of whether the details sit below the photo or beside it. You can save a different field list for each property type, so multifamily can lead with unit count while retail leads with rent, and you can give one listing its own layout from the Card Display section of the listing editor. The plugin follows automatically on the next cache refresh, or immediately if you have registered the webhook.

= Can I change how the listings look? =

Yes. Every element carries a stable CSS class, so you can restyle the grid entirely from Appearance to Customize to Additional CSS. The Settings to Core Listing screen lists the class names and shows example rules.

= Does the plugin work with the block editor? =

Yes. All three shortcodes are also registered as blocks under the widgets category, with sidebar controls for every filter and layout option and a live server rendered preview in the editor.

= Does the plugin collect any data about my visitors? =

No. It sets no cookies, adds no tracking scripts and never transmits visitor information. See the "External services" section above for the complete list of requests the plugin makes.

= Listings are not showing up. What should I check? =

Log in as an administrator and view the page. When something is misconfigured the plugin prints a short diagnostic, visible only to administrators, showing the URL it called and the HTTP status it received. Then confirm the Core Listing URL and API key on the settings screen and click "Test Connection".

== Screenshots ==

1. The shortcode or block rendered on the front end: a responsive grid of listing cards showing the photo and the fields chosen for that property type in Core Listing.
2. The Settings to Core Listing screen: URL, API key, Test Connection, Register Webhook and Clear Cache controls.
3. The "Core Listing Listings" block with its Inspector sidebar of filter and layout controls.
4. Core Listing, Integrations to WordPress: generate a scoped API key and review connected sites.

== Changelog ==

= 1.4.1 =
* Status banners such as "UNDER CONTRACT" and "SOLD" no longer lose an edge on the card. Photo boxes now use the ratio Core Listing bakes a banner at, so nothing is cropped off it.
* Cards set to "beside the photo" now use a square photo. That photo previously stretched to however tall the detail rows came out, so it had no fixed shape and a banner was cropped differently on every card.
* If your theme sets its own `aspect-ratio` on `.corelisting-photo`, banners will still lose their edges there. Remove the override to fix it.

= 1.4.0 =
* The shortcodes are now `[corelisting_listings]`, `[corelisting_sold]` and `[corelisting_members]`. They were `[crm_listings]`, `[crm_sold]` and `[crm_members]`, names generic enough to collide with another plugin on the same site. Any page still using an old name needs editing; the blocks are unchanged and keep working.

= 1.3.1 =
* Corrected the description of the new card arrangement: it is one brokerage-wide setting in Core Listing, not a per property type or per listing one. No change to how listings render.

= 1.3.0 =
* Listing cards can now show the details beside the photo instead of below it. Choose it once for your whole brokerage in Core Listing under Account Settings, Listing Display; this grid follows on the next cache refresh.
* Cards arranged that way carry a `.corelisting-card-side` class, and their grid carries `.corelisting-grid-side`, so a theme can restyle the arrangement.
* A grid of side by side cards uses two columns by default, since each card needs about twice the width. An explicit `columns` attribute is still honoured as written.
* On phones the details always fall back below the photo.

= 1.2.1 =
* Updating the plugin now clears its own listing cache. Previously an upgrade kept serving listings cached by the previous version for up to fifteen minutes, so a release that changed the card could look like it had not installed until you cleared the cache by hand.

= 1.2.0 =
* Listing cards now render the layout you configure in Core Listing under Account Settings, Listing Display, including a different layout per property type. Change it there and this grid follows on the next cache refresh.
* New CSS classes for the configured rows: `.corelisting-subhead`, `.corelisting-details`, `.corelisting-detail`, `.corelisting-detail-label`, `.corelisting-detail-value`, plus a per-field class such as `.corelisting-detail-price` on every row.
* Accounts on an older Core Listing release keep the previous card, so nothing changes until the layouts are available.

= 1.1.1 =
* Removed the Plugin URI header. It pointed at the same address as the Author URI, which the plugin directory rejects. The homepage describes the author, so only Author URI is kept.

= 1.1.0 =
* Prepared the plugin for the WordPress.org plugin directory: added the full GPLv2 license text, a License URI header, a Plugin URI header and a complete readme with an external services disclosure.
* Settings screen JavaScript is now enqueued as a proper script file instead of being printed inline, and is loaded only on the plugin's own settings page.
* Added a "Data sent to Core Listing" summary to the settings screen so the integration's network activity is visible where it is configured.
* Deactivating the plugin no longer contacts Core Listing. Only deleting the plugin releases the webhook registration, since deactivation is usually temporary.
* Text domain is now `core-listing` so translations load correctly from WordPress.org.
* Tested against WordPress 7.0.

= 1.0.18 =
* Settings screen now documents the `show_bio` attribute for `[crm_members]`, with an example.

= 1.0.17 =
* Team member cards now show the member's biography, set on the Core Listing team page for members flagged "Show on Team Page". Hide them with `[crm_members show_bio="no"]` or the "Show biographies" toggle on the block.

= 1.0.16 =
* `[crm_members]` and the Team Members block accept an `office` attribute (name or numeric ID) to scope the roster to one office.
* Documented that `[crm_sold]` accepts the same `office` filter as `[crm_listings]`.

= 1.0.15 =
* Plugin is now listed as "Core Listing" on the Plugins screen.
* Saving settings immediately re-fetches the account's confirmed white label domain, so the effective listing host is correct right away.

= 1.0.14 =
* Settings guidance now recommends entering your confirmed white label domain so listing images are served from your own host.
* All user facing copy now spells the product "Core Listing".

= 1.0.13 =
* Listing card links automatically use the account's confirmed white label custom domain when one is on file.
* Settings screen shows the effective listing URL host actually in use.
* The white label domain is cached locally and refreshed daily, so rendering makes no extra API call.

= 1.0.11 =
* Added license gated automatic updates for self hosted installs.

= 1.0.0 =
* Initial release.
* `[crm_listings]` shortcode and block, server rendered with no build step.
* Settings screen with Test Connection and webhook registration.
* REST webhook receiver with HMAC-SHA256 signature verification.
* Local transient cache, 15 minutes by default, flushed automatically on listing webhooks.

== Upgrade Notice ==

= 1.4.0 =
Breaking change: the shortcodes are renamed to [corelisting_listings], [corelisting_sold] and [corelisting_members]. Edit any page still using the old [crm_...] names after updating. Blocks are unaffected.

= 1.3.1 =
Wording fix in the plugin description only. No functional change.

= 1.3.0 =
Listing cards can now place the details beside the photo, set once for your whole brokerage in Core Listing. Existing layouts keep the details below the photo, so nothing changes until you choose otherwise.

= 1.2.1 =
Upgrades now clear the plugin's listing cache automatically, so a new card layout appears immediately instead of after the cache expires.

= 1.2.0 =
Listing cards now follow the layout configured in Core Listing, per property type. Custom CSS that targeted .corelisting-price, .corelisting-address, .corelisting-type or .corelisting-stat needs updating to the new row classes.

= 1.1.1 =
Header fix only. No functional change.

= 1.1.0 =
Directory readiness release. Deactivating the plugin no longer contacts Core Listing, and the text domain changed to core-listing. No settings or shortcodes change.
