Add an apartment listing and property search to WordPress: a plugin you can build today
· 5 min read
When you build a website for an apartment management company, the obvious move is to install a property management plugin. RentPress and RentFetch are the ones people try first. Both are built for operators who need lease management, resident portals, and maintenance request workflows. If your site needs to show twenty properties, let visitors filter by city, and link each one to a contact form, you are loading a commercial-grade system to solve a display problem.
The conflict problem compounds things. Specialist property plugins register their own templates, queue their own styles, and assume they own certain URL patterns. On a site using Astra or Blocksy with Elementor Pro already handling layout, the result is often visual breakage, duplicate database queries, or a settings screen that fights with the theme. The common advice is to find a more compatible plugin, but the more compatible options are usually other large plugins with the same assumptions.
A thin plugin that registers a Property post type, stores the fields a listing page needs, and gives you a shortcode to display a filterable card grid is the right tool for a small management company. Your Elementor layout stays in Elementor. The plugin provides only the data structure and the output block. No templates it insists you use, no styles forced into every page load, no admin screens that duplicate wp-admin.
What one build gives you
- Registers a Property custom post type with fields for address, city, state, bedrooms, rent range, and units available
- A City taxonomy with clean archive pages at /properties/city/{slug}/ that your theme renders without a custom template
- A [properties] shortcode with optional city= and state= parameters and a configurable limit
- Admin list columns showing City, Bedrooms, and Rent Range so you can scan the full inventory at a glance
- A Settings field to configure the enquiry button URL shown on each property card
What it does not do
- Map-based property search or plotting address fields as map pins
- Availability tracking, online lease applications, or tenant portals
- MLS or IDX data feed integration
- Radius search or price-range filter sliders beyond city and state text matching
- Multiple enquiry actions or per-property contact routing to different team members
RentPress does these. This covers the part most sites use.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin called Simple Property Listings. Plugin Name: Simple Property Listings. Description: A custom post type and shortcode for apartment and property directories. Single PHP file. Register a custom post type called property with label Properties, supports title editor thumbnail excerpt, menu_icon dashicons-building, has_archive true, rewrite slug properties, show_in_rest true. Register a custom taxonomy called property_city tied to the property post type with label City, hierarchical false, rewrite slug properties/city, show_in_rest true. Add a meta box titled Property Details to the property post type with these fields: Address (text, name _spl_address), State (text, name _spl_state), Bedrooms (text, placeholder 1-3 BR, name _spl_bedrooms), Rent range (text, placeholder $1,200-$2,400/mo, name _spl_rent_range), Units available (number, name _spl_units). Include a hidden nonce field spl_meta_nonce. On save_post, verify the nonce with wp_verify_nonce, check current_user_can edit_post, then update_post_meta for each field. Sanitize text fields with sanitize_text_field and units with absint. Add admin columns to the property post list screen: City (output the first property_city term name or a dash), Bedrooms (from _spl_bedrooms meta), Rent Range (from _spl_rent_range meta). Register these via manage_property_posts_columns and manage_property_posts_custom_column hooks. Register a shortcode [properties] with attributes city (term slug, default empty string), state (text, default empty string), limit (int, default 12). Build a WP_Query: post_type property, posts_per_page limit, post_status publish. If city is set add a tax_query for property_city with the term slug. If state is set add a meta_query for _spl_state LIKE matching the value. Loop the query and build the output: wrap everything in a div.spl-listings. For each post output a div.spl-card containing: h3 with an a tag linking to get_permalink, a span.spl-city with the property_city term names joined by comma, a p.spl-address showing the _spl_address meta and _spl_state meta together, a p.spl-details showing _spl_bedrooms and _spl_rent_range, a p.spl-excerpt with get_the_excerpt, and if get_option spl_contact_url is not empty an a.spl-enquire linking to that option value with target _blank and text Enquire. Call wp_reset_postdata after the loop. Return the output string. Output the following CSS via wp_head action with priority 20 using a style block: .spl-listings{display:flex;flex-wrap:wrap;gap:1.5rem;} .spl-card{flex:1 1 280px;border:1px solid #ddd;border-radius:6px;padding:1.25rem;background:#fff;} .spl-card h3{margin-top:0;} .spl-enquire{display:inline-block;margin-top:.75rem;padding:.5rem 1rem;background:#0073aa;color:#fff;border-radius:4px;text-decoration:none;} @media(max-width:600px){.spl-card{flex:1 1 100%;}} Add a submenu page under Settings with capability manage_options, menu slug simple-property-listings, title Property Listings Settings. Show a form with method POST, wp_nonce_field spl_settings, and one field: Contact URL (input type url, name spl_contact_url, value from get_option spl_contact_url). On POST with valid nonce and manage_options capability, update_option spl_contact_url using esc_url_raw on the submitted value. Show a success admin notice after saving.
Why specialist property plugins are overkill for most management sites
RentPress and similar plugins are built for large property management operators. They solve problems like syncing vacancy data from an external property management system, generating lease applications, routing maintenance requests, and managing resident logins. Those are real features for a company managing hundreds of units across multiple sites with a full office team behind them.
A company managing a dozen apartment complexes and using WordPress as their public marketing site needs none of that. They need a list of their properties with photos and details, city filtering so a visitor can narrow to a specific area, and a contact action on each property to start a conversation. That is three things, and it is the same job a blog with a custom post type has been doing for fifteen years.
The plugin described here does those three things and nothing else. It integrates with any theme because it adds no theme modifications. It does not register its own page templates, override the_content, or add global admin menus outside the Settings panel. It outputs one shortcode and gets out of the way.
What the plugin registers and stores
The plugin registers a Property custom post type with an archive at /properties/. Each property post has a title, a featured image, and an optional description in the main editor. A meta box on the edit screen adds the detail fields: Address, State, Bedrooms (a text field so you can write '1-3 BR'), Rent range (a text field so you can write '$1,200-$2,400/mo'), and Units available (a number).
City is registered as a separate taxonomy so each property can belong to one or more city terms. This gives you clean archive URLs at /properties/city/austin/ that your theme renders the same way any archive page is rendered, with no custom template required. The taxonomy and post type are both registered with show_in_rest true, so they appear in the block editor sidebar and work with the REST API.
The shortcode: filtering the listing by city or state
Adding [properties] to any page or Elementor shortcode widget outputs a responsive card grid of all properties. Each card shows the property name, city, address, bedrooms, rent range, excerpt, and an optional enquiry button. The shortcode accepts city='austin' (matched against the taxonomy slug), state='TX' (a case-insensitive text match against the State meta field), and limit= which defaults to 12.
The enquiry button links to a URL you configure in Settings under Settings > Property Listings Settings. It can be an email mailto: link, a contact page URL, or a WhatsApp link with a pre-filled message. If no URL is configured, the button is omitted. This keeps the plugin independent of whichever contact form plugin you are already running.
The card layout uses a small block of inline CSS: flex wrapping at 280px minimum width, a white card with a border and padding, and a single-column stack on screens narrower than 600px. The container sets no background, so it adapts to whatever your theme puts behind it.
When this is not the right approach
If the management company needs actual availability tracking, online lease applications, or a resident portal for maintenance requests, a thin CPT plugin is not the right tool. Those workflows need a proper property management platform with a WordPress integration, not a WordPress plugin pretending to be a platform.
If you need map-based search with a visible map and radius filtering, this plugin does not deliver that. It produces a text list with city and state filters. Adding a map is a natural second build: once the listing is working, ask Steem to add Leaflet.js integration that reads the address fields and plots pins on an interactive map.
If the property list will grow to several hundred entries, review whether a shortcode loop is still the right rendering approach. At that scale, a search index or server-side filter with pagination and faceted queries would serve visitors better than a single WP_Query pulling everything on page load.
Questions
- Do I need to rebuild my existing pages to use this?
No. The plugin adds a Property post type and one shortcode. Your existing pages are untouched. Add [properties] to any Elementor page using the Shortcode widget, or paste it directly into any classic editor page or text block.
- Will this plugin conflict with Astra, Blocksy, or Elementor Pro?
It should not. The plugin registers a post type and outputs a shortcode. It adds no global styles to other pages, overrides no theme templates, and makes no changes to your existing queries. The card styles are scoped to .spl-card so they do not leak into the rest of the site.
- Can I add a map showing all the property locations?
Not with this build. To add a map, ask Steem to add a second shortcode [properties_map] that loads Leaflet.js and geocodes the address fields. That is a second prompt once the listing is working and the addresses are entered.
- Can I import a list of properties from a spreadsheet instead of entering them one by one?
Not in this build. For a one-time import, the WP All Import plugin reads CSV files and can map columns to custom post meta including the fields this plugin registers. Ask Steem to add a CSV import screen to the plugin itself if you need repeatable bulk imports.
- How do I add an enquiry form to each individual property page?
Add your existing contact form shortcode to the property post content in the wp-admin editor. WPForms, Contact Form 7, or any form plugin that works on a standard post page will work on a property post. The plugin does not include its own form, it sits alongside whichever one you already have.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin called Simple Property Listings. Plugin Name: Simple Property Listings. Description: A custom post type and shortcode for apartment and property directories. Single PHP file. Register a custom post type called property with label Properties, supports title editor thumbnail excerpt, menu_icon dashicons-building, has_archive true, rewrite slug properties, show_in_rest true. Register a custom taxonomy called property_city tied to the property post type with label City, hierarchical false, rewrite slug properties/city, show_in_rest true. Add a meta box titled Property Details to the property post type with these fields: Address (text, name _spl_address), State (text, name _spl_state), Bedrooms (text, placeholder 1-3 BR, name _spl_bedrooms), Rent range (text, placeholder $1,200-$2,400/mo, name _spl_rent_range), Units available (number, name _spl_units). Include a hidden nonce field spl_meta_nonce. On save_post, verify the nonce with wp_verify_nonce, check current_user_can edit_post, then update_post_meta for each field. Sanitize text fields with sanitize_text_field and units with absint. Add admin columns to the property post list screen: City (output the first property_city term name or a dash), Bedrooms (from _spl_bedrooms meta), Rent Range (from _spl_rent_range meta). Register these via manage_property_posts_columns and manage_property_posts_custom_column hooks. Register a shortcode [properties] with attributes city (term slug, default empty string), state (text, default empty string), limit (int, default 12). Build a WP_Query: post_type property, posts_per_page limit, post_status publish. If city is set add a tax_query for property_city with the term slug. If state is set add a meta_query for _spl_state LIKE matching the value. Loop the query and build the output: wrap everything in a div.spl-listings. For each post output a div.spl-card containing: h3 with an a tag linking to get_permalink, a span.spl-city with the property_city term names joined by comma, a p.spl-address showing the _spl_address meta and _spl_state meta together, a p.spl-details showing _spl_bedrooms and _spl_rent_range, a p.spl-excerpt with get_the_excerpt, and if get_option spl_contact_url is not empty an a.spl-enquire linking to that option value with target _blank and text Enquire. Call wp_reset_postdata after the loop. Return the output string. Output the following CSS via wp_head action with priority 20 using a style block: .spl-listings{display:flex;flex-wrap:wrap;gap:1.5rem;} .spl-card{flex:1 1 280px;border:1px solid #ddd;border-radius:6px;padding:1.25rem;background:#fff;} .spl-card h3{margin-top:0;} .spl-enquire{display:inline-block;margin-top:.75rem;padding:.5rem 1rem;background:#0073aa;color:#fff;border-radius:4px;text-decoration:none;} @media(max-width:600px){.spl-card{flex:1 1 100%;}} Add a submenu page under Settings with capability manage_options, menu slug simple-property-listings, title Property Listings Settings. Show a form with method POST, wp_nonce_field spl_settings, and one field: Contact URL (input type url, name spl_contact_url, value from get_option spl_contact_url). On POST with valid nonce and manage_options capability, update_option spl_contact_url using esc_url_raw on the submitted value. Show a success admin notice after saving.
Steem