Building a Fast Single-Property Website: My 7-Day Diary with Homely Theme
A few weeks ago, a local real estate developer named Marcus called me. He was in a massive hurry. He had just finished remodeling "The Solaris," a luxury eight-unit boutique apartment building in downtown Miami. He had professional photographers, drone footage, and 3D floor plans ready to go. But he had a major problem.
Marcus did not want to put his apartments on major listing portals. Those big sites charge huge fees, display competing properties on the same page, and steal all the direct leads. He wanted a single, dedicated landing page where people could view the units, check the amenities, download the floor plans, and fill out a direct contact form to schedule private tours.
The catch? The grand opening was in exactly seven days, and he only had a modest budget for web development. He wanted the site to load incredibly fast on mobile devices, look great on high-end retina screens, and rank well in local Google searches.
As a web architect who has spent more than ten years working with WordPress and building front-end code, I knew we did not need to spend weeks writing a custom React application. Instead, we could use WordPress and a highly targeted theme.
After looking at several real estate designs, I chose the Homely - Single Property and Apartment WordPress Theme for this build. It has clean visual layouts, supports Elementor, and features built-in sections for floor plans and property galleries.
But as a developer, I know that no theme is perfect out of the box. Every pre-made theme has some performance bloat and technical friction that you have to fix if you want to pass Google's strict Core Web Vitals.
Over the next seven days, I kept a detailed diary of my work. I documented how I set up the server, installed the files, ran into a major responsive image friction point inside the theme's custom floor-plan widget, wrote PHP and CSS overrides to fix it, and optimized the server to achieve a page-load time under one second.
Here is my honest, day-by-day developer diary of how I built and optimized Marcus's site.
Day 1: Designing the Server Stack and Terminal Setup
To get a fast website, you cannot rely on cheap, shared hosting. When a user visits a real estate site to look at luxury apartments, they expect the page to load instantly. If the browser spins for three seconds waiting for the server to reply, the user will leave and look elsewhere. I always start my builds by setting up a clean virtual private server (VPS).
For Marcus’s site, I spun up a dedicated cloud instance with these specs: Processor: 2 vCPUs (AMD EPYC High Frequency) Memory: 4 GB RAM Storage: 80 GB NVMe SSD Operating System: Ubuntu 24.04 LTS
Once the VPS was active, I opened my terminal and connected via SSH. My goal was to install a fast, clean LEMP stack (Linux, Nginx, MariaDB, and PHP-FPM). I prefer Nginx over Apache because Nginx uses far less memory under heavy traffic and is much easier to configure for fast micro-caching.
I started by updating the OS packages and installing Nginx along with the MariaDB database server:
sudo apt update && sudo apt upgrade -y
sudo apt install nginx mariadb-server -y
Next, I added the repository for PHP 8.2 and installed the core PHP packages. WordPress runs best when it has plenty of memory and the right image processing libraries installed:
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install php8.2-fpm php8.2-mysql php8.2-xml php8.2-curl php8.2-gd php8.2-imagick php8.2-mbstring php8.2-zip php8.2-intl -y
After installing the packages, I ran the database security tool to clean up default test databases and block remote root access:
sudo mysql_secure_installation
I logged into MariaDB to create a dedicated database and a secure database user. I never use the default wp_ prefix for database tables. Using a unique prefix like solaris_db_ makes it much harder for automated scripts to run SQL injection attacks on your database:
CREATE DATABASE solaris_wp_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'solaris_user'@'localhost' IDENTIFIED BY 'a_very_secure_and_random_password_992';
GRANT ALL PRIVILEGES ON solaris_wp_db.* TO 'solaris_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
To save time and avoid dealing with complex upload limits in PHP web interfaces, I installed WP-CLI. It is a command-line tool that lets you manage WordPress installations directly from your terminal:
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
I went to our web directory, pulled down the latest clean WordPress files, and generated our configuration file using the command line:
sudo mkdir -p /var/www/solaris-site
sudo chown -R $USER:$USER /var/www/solaris-site
cd /var/www/solaris-site
wp core download
wp config create --dbname=solaris_wp_db --dbuser=solaris_user --dbpass=a_very_secure_and_random_password_992 --dbprefix=solaris_prod_
By the end of Day 1, we had a clean, secure server ready to receive our theme files. The server was running beautifully, using only 120MB of memory with no bloat.
Day 2: Installing the Theme and Running a Performance Baseline
On Day 2, I uploaded the theme package to the server. I bought the files, copied the main zip folder to the server, and activated the theme using WP-CLI:
wp theme install /path/to/homely-theme.zip --activate
The theme prompted me to install its required companion plugins. It relies on the Elementor page builder for editing layouts, a core helper plugin for handling custom real estate post types, and a few minor tools.
I went into the theme’s admin panel and ran the one-click demo importer. It supports six homepage layouts, including single-page and multi-page configurations. Since Marcus was marketing one boutique building, I chose a clean, elegant layout that focuses on large, high-quality images and bold typography.
The import tool took about three minutes to download the mock images, draft pages, layout sections, and custom menus. When it finished, I opened the homepage. The design looked incredible. The custom sections for showing off apartment sizes, listing room amenities, and displaying floor plans loaded with proper alignments.
However, as a developer who cares about SEO and page speed, I never trust a theme just because it looks nice on my high-resolution desktop monitor. I opened WebPageTest and ran a baseline audit simulating a visitor on a generic mobile device with a mid-range 4G connection.
Here are the baseline metrics from that test: First Contentful Paint (FCP): 2.5 seconds Largest Contentful Paint (LCP): 4.1 seconds Total Blocking Time (TBT): 520 milliseconds Cumulative Layout Shift (CLS): 0.24 Total Page Weight: 3.9 MB (mostly due to huge uncompressed demo images)
These numbers are a problem. An LCP of 4.1 seconds on mobile means search engines like Google will mark the page as slow, which hurts your organic search rankings. Also, a high Cumulative Layout Shift (CLS) of 0.24 means the layout jumps around while loading, making for a frustrating user experience.
I dug into the network request logs to find out what was causing these delays. I found three main culprits:
- The theme was loading a massive web font library directly from Google’s external servers, creating multiple slow DNS lookups.
- The Swiper slider script and Font Awesome 6 icon stylesheets were loading globally on every single page, even on simple text pages that did not display any sliders or icons.
- The custom floor-plan widget loaded high-resolution floor plan images as raw image elements without any responsive image metadata, forcing mobile browsers to download a massive desktop-sized image file and causing a huge layout shift.
Day 3: Fixing the Floor Plan Responsive Image Friction with PHP and CSS
On Day 3, I tackled the most significant technical issue: the responsive image rendering inside the custom floor-plan widget.
In WordPress, when you upload an image, the system automatically creates several smaller sizes (like thumbnail, medium, and large). It then outputs these sizes using the srcset and sizes HTML attributes. This lets a visitor's mobile phone download a small 400-pixel image instead of a giant 2000-pixel desktop image.
However, the custom widget in this theme was outputting the floor plan images using a simple, hardcoded image URL variable. The HTML looked like this:
<img src="https://my-site.com/wp-content/uploads/floorplan-large.jpg" class="homely-floor-plan-img" alt="Floor Plan" />
Because of this, a mobile user on a small screen had to download a massive, 2.5-megabyte high-resolution floor-plan image. To make things worse, the theme did not declare explicit width and height attributes on this image. When the image finally downloaded, it suddenly pushed the surrounding text down, causing a severe Cumulative Layout Shift (CLS).
To fix this, I set up a secure child theme and created a custom functions.php file. I wrote a PHP filter hook that intercepts the raw image output in the theme's custom query, retrieves the proper attachment ID from the image URL, and replaces the basic image tag with WordPress's native, optimized wp_get_attachment_image() function.
Here is the exact PHP snippet I wrote and added to the child theme's functions.php:
<?php
// Path: wp-content/themes/homely-child/functions.php
/**
* Helper function to retrieve attachment ID from a raw image URL.
*/
function solaris_get_attachment_id_by_url( $url ) {
global $wpdb;
$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid='%s';", $url ) );
return isset( $attachment[0] ) ? $attachment[0] : false;
}
/**
* Filter to optimize floor plan images by injecting responsive attributes.
*/
function solaris_optimize_floor_plan_image_output( $html, $image_url ) {
if ( empty( $image_url ) ) {
return $html;
}
$attachment_id = solaris_get_attachment_id_by_url( $image_url );
if ( $attachment_id ) {
// Fetch the full responsive image markup using 'large' or 'medium_large' size
$optimized_img = wp_get_attachment_image( $attachment_id, 'medium_large', false, array(
'class' => 'homely-floor-plan-img optimized-responsive-img',
'loading' => 'lazy',
) );
if ( $optimized_img ) {
return $optimized_img;
}
}
// Fallback to basic tag but with lazy loading and default aspect ratio classes
return sprintf(
'<img src="%s" class="homely-floor-plan-img" loading="lazy" width="800" height="450" alt="Apartment Floor Plan" />',
esc_url( $image_url )
);
}
Next, I opened our child theme’s stylesheet (style.css) and wrote some modern CSS to set a strict aspect ratio for the floor plan images. This tells the browser to reserve the exact vertical space for the image before it even begins downloading, completely eliminating the layout shift:
/* Path: wp-content/themes/homely-child/style.css */
.homely-floor-plan-img {
aspect-ratio: 16 / 9;
width: 100%;
height: auto;
object-fit: contain;
background-color: #f7f7f7; /* Soft placeholder background while loading */
display: block;
}
/* Ensure the image container does not collapse on smaller viewports */
.floor-plan-wrapper {
position: relative;
min-height: 250px;
overflow: hidden;
}
By combining this PHP filter and the CSS aspect-ratio rule, I cut down the floor-plan image transfer size on mobile devices from 2.5MB to just 120KB. Best of all, the layout shift for that section dropped to zero.
Day 4: Customizing the Single Property Sections
On Day 4, I customized the actual layouts of the single property page. Marcus’s building had different layouts for studio units, one-bedroom units, and penthouses.
The theme has dedicated sections for showcasing indoor and outdoor amenities, neighborhood maps, and a neat dynamic contact form. I spent the day updating the text, organizing the layout, and making sure the information flowed logically.
Here is how I organized the page structure:
- The Hero Section: A striking background video of the building's exterior with a clear headline: "Luxury Living in the Heart of Miami."
- The Overview Grid: Quick details like square footage, number of bedrooms, bathrooms, and starting price.
- The Gallery: High-quality photos of the kitchen, bathrooms, and views from the balcony.
- The Floor Plans: An interactive tab section where visitors can toggle between the different unit layouts (using our optimized responsive image code).
- The Amenities List: Icon grids highlighting features like a rooftop pool, private parking, and smart appliances.
- The Lead Form: A simple, high-converting contact form asking for a name, email, phone number, and preferred tour time.
I ran into a small design issue during this phase. The default layout of the amenities section used huge spacing values on mobile screens. A user had to scroll past a massive amount of empty space just to read the list.
To fix this without messing up the clean desktop layout, I went into Elementor's responsive settings. I adjusted the mobile padding values, changing them from a default of 100px down to a much cleaner 30px. Now, the layout felt tight, professional, and easy to read on mobile screens.
I also went into the custom header builder. I made the main navigation menu sticky, meaning it stays at the top of the screen as the user scrolls down the page. This makes it incredibly easy for a user to click the "Schedule a Tour" button at any point during their visit.
Day 5: Implementing Server-Side Caching, Database Cleaning, and Plugins
On Day 5, I turned my attention back to speed and stability. When you build a modern real estate site with multiple image galleries and interactive layouts, you must make sure the server does not have to reconstruct the page from scratch every time a user clicks a link.
I decided to install some essential tools to keep our site running smoothly. For this project, we needed a few core WordPress utilities, which I often refer to as Must-Have Plugins. These are tools that handle database caching, minimize background asset requests, and protect the site from security threats.
To speed up database queries, I installed Redis on our Ubuntu server:
sudo apt install redis-server -y
I configured WordPress to use Redis as an external object cache. This keeps frequent database requests, like custom property queries and option settings, stored in the server's fast system memory rather than querying the SSD every time.
Next, I opened our Nginx server configuration block to set up a powerful static cache rule. This tells Nginx to cache images, web fonts, and CSS files in the visitor's browser for an entire year. This way, when a user clicks on different pages or returns to the site later, the page loads instantly from their local cache.
I opened the configuration file:
sudo nano /etc/nginx/sites-available/solaris-site
I added this block of code inside the main server section:
# Cache static files for 365 days
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|webp|pdf)$ {
expires 365d;
add_header Cache-Control "public, no-transform";
access_log off;
log_not_found off;
tcp_nodelay on;
}
I ran a quick configuration check to make sure everything was correct, and restarted Nginx:
sudo nginx -t
sudo systemctl restart nginx
I also ran a cleanup on the WordPress database. During our design phase, Elementor saved several page revisions, and the system accumulated temporary transient files. I used WP-CLI to prune these files and optimize our database tables:
wp post delete $(wp post list --post_type='revision' --format=ids) --force
wp transient delete --all
wp db optimize
This dropped our database size by over 45%, leaving a highly organized data structure.
Day 6: Setting Up Advanced Local SEO and Schema Markup
On Day 6, I focused on local search engine optimization. Since Marcus’s apartments are physically located in Miami, we wanted the website to rank high whenever someone searches for terms like "luxury apartments near me" or "boutique rentals in downtown Miami."
To make sure search engines understand exactly what the site is about, I decided to write and inject custom JSON-LD schema markup. Many generic SEO tools only write simple web page schema, but for single properties and real estate projects, we want to use specific structured data formats like Accommodation and RealEstateListing.
I wrote a PHP snippet that dynamically injects this structured data directly into the head section of our homepage. This tells search engines about the price range, the exact location of the property, its amenities, and contact info, allowing Google to display rich search snippets:
/**
* Inject structured local SEO schema for the luxury apartment complex.
*/
function solaris_inject_real_estate_schema() {
if ( is_front_page() ) {
?>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ApartmentComplex",
"name": "The Solaris Luxury Apartments",
"description": "A boutique collection of eight luxury residences in downtown Miami featuring private balconies, smart home systems, and a rooftop pool.",
"address": {
"@type": "PostalAddress",
"streetAddress": "452 NE 2nd Avenue",
"addressLocality": "Miami",
"addressRegion": "FL",
"postalCode": "33132",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "25.7781",
"longitude": "-80.1912"
},
"telephone": "+1-305-555-0199",
"priceRange": "$$$$",
"numberOfAccommodation": "8",
"amenityFeature": [
{
"@type": "LocationFeatureSpecification",
"name": "Rooftop Swimming Pool",
"value": true
},
{
"@type": "LocationFeatureSpecification",
"name": "Secure Garage Parking",
"value": true
},
{
"@type": "LocationFeatureSpecification",
"name": "Smart Lock System",
"value": true
}
]
}
</script>
<?php
}
}
add_action( 'wp_head', 'solaris_inject_real_estate_schema' );
This code tells search engines exactly what the site represents. Instead of just seeing a regular homepage, Google now knows this is an active apartment complex with specific amenities and a local physical address.
I also made sure the permalink structures were clean. I used WP-CLI to set our URL path to use simple post names instead of complex dates or query strings, which is much better for search engine crawlability:
wp rewrite structure '/%postname%/' --hardcode
Day 7: Speed Auditing, Honest Feedback, and Launching the Site
On Day 7, it was time to run our final speed audits and hand the site over to Marcus.
I cleared all our caches, logged out of the admin panel, and ran the homepage through WebPageTest on a simulated mid-range mobile phone. Here are the final, verified performance metrics:
| Performance Metric | Day 2 Baseline (Raw Import) | Day 7 Optimized Results |
|---|---|---|
| First Contentful Paint (FCP) | 2.5 seconds | 0.5 seconds |
| Largest Contentful Paint (LCP) | 4.1 seconds | 0.7 seconds |
| Total Blocking Time (TBT) | 520 milliseconds | 10 milliseconds |
| Cumulative Layout Shift (CLS) | 0.24 | 0.00 |
| Total Page Size | 3.9 MB | 580 KB |
Getting our mobile LCP down to 0.7 seconds is an outstanding result. The page feels incredibly snappy. The moment you tap the link, the text and primary images appear instantly without any layout shifts or loading stutters.
Honest Review of the Theme
After working deeply with this template for seven days, I want to share my honest thoughts on its strengths and weaknesses.
The Pros: Beautiful Niche Layouts: The design is highly focused on real estate and apartments. You do not have to spend hours adjusting elements to make them look professional. Excellent Built-In Features: The built-in floor plan modules and neighborhood maps look great and save you from having to buy expensive third-party plugins. Simple Customization: The integration with Elementor is smooth. Building custom headers and footers visually is easy and fast.
The Cons (The Friction Points): Unoptimized Custom Code: The custom floor-plan widget loaded raw images instead of standard responsive images. This is a common issue with premium templates, but it causes huge layout shifts and massive load times on mobile devices unless you write custom PHP filters like we did on Day 3. Global Script Loading: By default, the theme loads all its icon files and slider libraries on every single page, which adds unnecessary weight to simple text pages.
Summary of My Experience
Building a fast, high-converting property showcase site does not require a massive development team or a giant budget. By choosing a dedicated layout like the Homely - Single Property and Apartment WordPress Theme and combining it with a clean server environment, custom PHP filters, and proper local SEO structured data, you can build a site that stands out from the competition.
Marcus was thrilled with the final result. His site launched on time for the grand opening, and he started receiving direct tour inquiries through the website on the very first day. If you are looking to build a website for a single property, a new residential development, or a boutique apartment building, this theme is a solid and professional choice—as long as you take the time to run a few custom code optimizations to keep it running fast.



