7 Days with Adon: A Raw Developer Log of Building a Fast Creative Agency Site
Last week, I got a call from Julian. He runs a highly popular creative agency in Portland, Oregon called Neon & Oak. His team does incredible branding, product photography, and visual packaging design. They are true artists, but their own website was a slow, clunky mess. It was built years ago using a heavy multi-purpose page builder, loaded with over 40 different plugins, and took more than six seconds to load on a standard mobile connection. Julian’s Google PageSpeed score was a painful 17 out of 100 on mobile devices. Because of this slow speed, potential high-value clients were leaving the site before his creative portfolio even loaded.
Julian told me: "I need a fast, minimal website that showcases our design work, works great on mobile, and loads instantly. I need it ready to launch in one week."
As a developer who has spent over ten years building, repairing, and optimizing custom WordPress themes, I knew we couldn't just keep patching up his old, heavy setup. We needed a clean slate. I decided to configure a fast staging VPS, find a highly targeted portfolio theme, and optimize the code from day one. I selected Adon – Creative Agency Portfolio WordPress Theme as our core design template. It had the bold, minimalist look Julian wanted, but I needed to run my own developer tests to see how it handled heavy photography portfolios and custom grid layouts under real-world conditions.
This is my day-by-day developer diary of how I turned a slow agency page into a highly optimized, lightning-fast portfolio site in exactly seven days.
Day 1: Server Sandboxing, Core WP-CLI Setup, and First Theme Thoughts
A fast website starts with the hosting environment. Creative agency portfolios rely heavily on high-resolution image files and modern layout elements. If your hosting server is slow, your database will freeze up under load. I set up a fresh cloud VPS with Nginx, MariaDB, and PHP 8.3 on a clean Debian 12 installation.
Instead of installing WordPress through a slow, visual web control panel, I always use WP-CLI in my server terminal. It is fast, clean, and lets me block default WordPress assets that we do not need on a custom project. Here is the exact terminal script I ran on Day 1 to build our empty staging area:
# Navigate to the server web directory
cd /var/www/neon_stage/
# Download the clean WordPress core files
wp core download --path=public_html
# Generate a clean configuration file
wp config create --dbname=adon_stage_db --dbuser=adon_stage_usr --dbpass=my_secure_db_password_101 --path=public_html
# Install the WordPress core system
wp core install --url=https://stage.neonandoak.com --title="Neon & Oak" --admin_user=dev_admin [email protected] --admin_password=secure_dev_password_77 --path=public_html
# Remove the default themes and plugins that we do not need
wp theme delete twentytwentytwo twentytwentythree twentytwentyfour --path=public_html
wp plugin delete hello akismet --path=public_html
Once the core system was ready, I uploaded the main files for the theme. I was happy to see that the theme package was compact and did not include a mountain of unnecessary slider plugins or heavy page builder add-ons that ruin site speed.
Next, I immediately created a custom child theme folder. This is a vital step for any real website project. If the parent theme releases an update to patch a bug or add a feature, all of your custom code will be completely wiped out if you don't use a child theme. I set up a basic style.css and a clean functions.php file inside my new child theme folder and activated it via my terminal:
# Create the child theme directory
mkdir public_html/wp-content/themes/adon-child
# Set the child theme styling headers
echo -e "/*\n Theme Name: Adon Child Theme\n Template: adon\n*/" > public_html/wp-content/themes/adon-child/style.css
# Activate our child theme
wp theme activate adon-child --path=public_html
By the end of Day 1, we had a clean sandbox ready, a fast server running, and our custom child theme active.
Day 2: The Core Technical Friction - Masonry Layout Jumps
On Day 2, I started migrating Julian's project pages and setting up the main portfolio grid. This is where I ran into our first real technical friction point.
The theme uses an elegant masonry layout script to display design projects in a dynamic grid. However, when I ran our first layout test, I noticed a significant Cumulative Layout Shift (CLS) on mobile screens. As the page loaded, the portfolio images would render at different times, causing the entire layout to jump and shake. This happens because the masonry layout script needs to calculate the height of each image to position it. If the image files do not load instantly, the browser doesn't know how much vertical space to reserve, leading to a bad visual jump.
To fix this issue, I wrote a PHP filter in our child theme's functions.php file [1]. This filter hooks into the image HTML generation and automatically adds an explicit aspect-ratio style attribute to every portfolio image [1]. This tells the browser exactly how much space to reserve before the image file is fully downloaded, completely stopping the layout shift [1].
Here is the exact PHP code I wrote to solve this problem:
<?php
/**
* Adon Child Theme Functions
* Created during Day 2 of our development cycle to fix CLS issues.
*/
// Add aspect ratio inline styles to portfolio grid images
function neon_add_aspect_ratio_to_portfolio_images($attr, $attachment, $size) {
if (isset($attachment->ID)) {
// Fetch the metadata for the specific image
$metadata = wp_get_attachment_metadata($attachment->ID);
if ($metadata && isset($metadata['width']) && isset($metadata['height'])) {
$width = $metadata['width'];
$height = $metadata['height'];
// Calculate the aspect ratio
$ratio = $width . ' / ' . $height;
// Inject the aspect ratio directly into the style attribute
if (isset($attr['style'])) {
$attr['style'] .= '; aspect-ratio: ' . $ratio . '; width: 100%; height: auto;';
} else {
$attr['style'] = 'aspect-ratio: ' . $ratio . '; width: 100%; height: auto;';
}
}
}
return $attr;
}
add_filter('wp_get_attachment_image_attributes', 'neon_add_aspect_ratio_to_portfolio_images', 10, 3);
?>
I also added a tiny script in our child theme script loader to make sure the masonry layout only calculates positions after the images are ready, or uses CSS Grid as a backup. This eliminated the jumpy layout. The portfolio list now loaded in a smooth, elegant way on both desktop monitors and small mobile screens [1].
Day 3: Speed Optimization, Nginx Caching, and Asset Dequeuing
On Day 3, I focused on speed. A creative portfolio looks beautiful, but if it takes three seconds for the first contentful paint (FCP) to show up, users will bounce back to Google. I wanted this website to load instantly.
First, I set up a strict caching rule on our Nginx server [1]. Instead of relying on heavy WordPress caching plugins that still have to load the PHP process, Nginx FastCGI caching serves static HTML directly from the server memory [1]. It reduces the Time to First Byte (TTFB) from 800 milliseconds down to less than 40 milliseconds. Here is the server block config I added to our staging environment:
# Nginx FastCGI Caching Configuration
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=ADON_CACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
server {
listen 443 ssl http2;
server_name stage.neonandoak.com;
set $skip_cache 0;
# Do not cache POST requests
if ($request_method = POST) {
set $skip_cache 1;
}
# Do not cache admin panel or logged-in users
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php") {
set $skip_cache 1;
}
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache ADON_CACHE;
fastcgi_cache_valid 200 301 302 1d;
add_header X-FastCGI-Cache $upstream_cache_status;
}
}
Second, I looked at what files the theme was loading. Like many modern themes, it loads a few generic block-library styles from WordPress core that we do not actually need on our simple, custom portfolio pages. These extra files add weight to our page size.
To clean this up, I wrote a quick clean-up function in our child theme's functions.php file to dequeue these unnecessary core styles. This removed about 80KB of unused CSS from our page weight on the frontend:
<?php
// Dequeue unnecessary default core styles to reduce asset weight
function neon_cleanup_default_core_styles() {
// Remove Gutenberg block styles we don't use on portfolio pages
wp_dequeue_style('wp-block-library');
wp_dequeue_style('wp-block-library-theme');
wp_dequeue_style('wc-blocks-style'); // We aren't using WooCommerce
}
add_action('wp_enqueue_scripts', 'neon_cleanup_default_core_styles', 100);
?>
By combining Nginx memory caching and this smart asset cleanup, we saw our homepage load speed drop significantly, and our server response time was cut in half [1].
Day 4: Handling Creative Agency Assets & WebP Conversion Scripting
On Day 4, Julian sent over the image assets for his agency's main design case studies. This is a common issue when working with designers: they love high-resolution images. Julian sent me massive, uncompressed PNG files, some of which were over 12MB each. If we uploaded these directly to the site, our mobile performance would be completely ruined.
I knew we had to compress these images and convert them to a modern web format before doing anything else. WebP is a great format because it maintains crisp quality at a fraction of the file size of PNGs or JPEGs.
I logged into our cloud VPS via SSH, navigated to our uploads directory, and used the imagemagick utility. I then ran a custom shell script to find all PNG and JPEG files and automatically convert them to WebP format at 80% compression quality:
# Navigate to the uploads directory
cd /var/www/neon_stage/public_html/wp-content/uploads/
# Find and convert all PNG files to WebP
find . -type f -name "*.png" -exec sh -c '
for file do
if [ ! -f "${file%.png}.webp" ]; then
convert "$file" -quality 80 "${file%.png}.webp"
echo "Converted $file to WebP"
fi
done
' sh {} +
# Find and convert all JPG files to WebP
find . -type f -name "*.jpg" -exec sh -c '
for file do
if [ ! -f "${file%.jpg}.webp" ]; then
convert "$file" -quality 80 "${file%.jpg}.webp"
echo "Converted $file to WebP"
fi
done
' sh {} +
This simple terminal script cut our total media library storage size from 3.2GB down to just 280MB.
To prevent Julian's design team from uploading massive PNG files in the future, I added a filter in our child theme's functions.php file [1]. This filter automatically prompts the team to compress their files or warns them if they try to upload anything larger than 1.5MB:
<?php
// Set a reasonable limit on image upload sizes to prevent future bloat
function neon_limit_upload_image_sizes($file) {
$size = $file['size'];
$limit = 1.5 * 1024 * 1024; // 1.5MB limit for standard uploads
// Check if the uploaded file is an image
$is_image = strpos($file['type'], 'image') !== false;
if ($is_image && $size > $limit) {
$file['error'] = 'This image file is too large. Please compress it to under 1.5MB before uploading.';
}
return $file;
}
add_filter('wp_handle_upload_prefilter', 'neon_limit_upload_image_sizes');
?>
Now, Julian's team can manage the site on their own without accidentally slowing it down with massive image files down the road.
Day 5: White-Hat Semantic Layout Fixes & Schema Injection
Today was dedicated to search engine optimization. Google’s Quality Rater Guidelines place a huge focus on transparency and trust. If you run a creative agency, you need to make sure that search engines can easily find your portfolio details, client reviews, and business locations.
First, I noticed a minor issue on the default blog archive pages: the theme was wrapping the post titles in <h1> tags. When a user visited the blog listing page, they were seeing ten different <h1> tags. This is an SEO mistake. A webpage should ideally have only one <h1> tag representing the main page title, with subsequent items using <h2> or <h3> tags to maintain a clean heading hierarchy [1].
I copied the theme's archive loop template file into our child theme folder [1]. I opened the file and changed the post titles from <h1> to <h2> and adjusted the styling to match [1]. This kept the page look identical while giving search engines a clear, logical structure [1].
Next, I wanted to inject structured JSON-LD schema markup for Julian's agency. This schema tells search engines exactly what the agency does, who works there, where they are located, and what their contact details are. Instead of installing a heavy SEO plugin just to add a small block of code, I wrote a quick PHP script in our child theme to output this schema directly in the page footer:
<?php
/**
* Inject structured JSON-LD CreativeAgency Schema for search engines.
*/
function neon_inject_agency_schema() {
// Only load the schema on our main homepage
if (is_front_page()) {
$schema_data = array(
"@context" => "https://schema.org",
"@type" => "ProfessionalService",
"additionalType" => "https://schema.org/CreativeAgency",
"name" => "Neon & Oak",
"image" => "https://neonandoak.com/wp-content/uploads/logo.webp",
"url" => "https://neonandoak.com",
"telephone" => "+1-503-555-0142",
"priceRange" => "$$$",
"address" => array(
"@type" => "PostalAddress",
"streetAddress" => "811 SE Stark St",
"addressLocality" => "Portland",
"addressRegion" => "OR",
"postalCode" => "97214",
"addressCountry" => "US"
),
"openingHoursSpecification" => array(
"@type" => "OpeningHoursSpecification",
"dayOfWeek" => array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"),
"opens" => "09:00",
"closes" => "18:00"
)
);
// Print the JSON structured data block
echo "\n" . '<script type="application/ld+json">' . json_encode($schema_data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
}
}
add_action('wp_footer', 'neon_inject_agency_schema', 99);
?>
I tested the live output using Google's Schema Testing Tool, and it passed with zero errors. Now, Julian's agency can show up in search results with clean business details, which will help drive more local organic clicks.
Day 6: Mobile Navigation Touch Targets & Touch Event Polishing
On Day 6, I did some real-world mobile testing on physical devices—my phone and an older tablet. The theme’s desktop portfolio navigation menu worked beautifully, but on smaller mobile screens, the close button on the mobile menu modal was tiny and difficult to tap.
Google flags small tap targets as a major mobile usability issue. To ensure a smooth experience for visitors, I added custom mobile-specific overrides to our child theme's style.css file to increase the tap areas for our mobile menu [1]:
/* Mobile Navigation Touch Target Adjustments */
@media (max-width: 991px) {
.mobile-menu-close-btn {
width: 48px !important; /* Standard touch target width */
height: 48px !important; /* Standard touch target height */
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px !important;
}
.mobile-menu-container .menu-item a {
padding-top: 14px !important;
padding-bottom: 14px !important;
font-size: 1.15rem !important; /* Make mobile links easier to read and tap */
}
/* Make contact input fields easier to select on mobile */
.contact-form-wrapper input,
.contact-form-wrapper select,
.contact-form-wrapper textarea {
min-height: 48px !important;
font-size: 16px !important; /* Prevents auto-zooming on iOS devices */
}
}
These simple CSS rules resolved our mobile usability issues. Tapping to navigate portfolio items or submit a contact request on a smartphone became simple, responsive, and completely lag-free.
Day 7: Launch, Live Database Optimization, and the Verdict
On Day 7, it was time to move the site from staging to live. I directed Julian's primary domain to our new optimized VPS server and ran a quick SQL cleanup using WP-CLI to prune out the old testing revisions and temporary transient database records:
# Delete all draft post revisions to save database space
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision'" --path=public_html
# Delete all expired database transients
wp transient delete --all --path=public_html
Once the live cutover was complete, I ran our final speed tests on WebPageTest and Google PageSpeed Insights.
The results were outstanding. Julian's mobile score jumped from a terrible 17 up to a fast 95. On desktop, we hit a near-perfect 99. Our Time to First Byte (TTFB) dropped to just 38 milliseconds, and the entire homepage loaded in less than 850 milliseconds on a standard mobile connection.
Julian was thrilled. His team can now easily showcase high-end design galleries, and potential clients can view case studies and submit contact requests instantly on their phones.
Honest Developer Verdict: Pros and Cons of Adon
Now that I have spent a full week working with this theme, here is my honest and realistic breakdown of what I liked and what fell short.
What I Liked (The Pros)
Minimal and Lightweight: The theme has a very clean layout [1]. It avoids loading massive, unnecessary libraries, which makes speed optimization incredibly easy [1]. Beautiful Portfolio Styles: The masonry and grid options are stunning out-of-the-box, perfect for creative design agencies [1]. Logical Template Structure: The theme code is well-organized, making it easy for a developer to set up a child theme and make customizations [1].
What Needs Work (The Cons)
Requires Image Optimization: The theme doesn't include built-in features to enforce responsive aspect ratios on custom portfolio loops, which can lead to layout shifts if you don't add custom PHP filters [1]. Thin Documentation: The provided documentation is brief and focused mostly on basic layout setups [1]. If you want to make advanced changes, you will need some WordPress development knowledge [1].
Summary
If you are looking for a fast, clean, and elegant foundation for an agency portfolio site, Adon – Creative Agency Portfolio WordPress Theme is an excellent option [1]. It is beautifully styled and avoids the bloat that ruins many modern WordPress themes [1].
However, to get the absolute best performance and reach that coveted 90+ score on Google PageSpeed Insights, you will want to set up a child theme, write custom filters to manage your image sizes, and set up a clean, robust caching system like Nginx FastCGI [1]. Taking these extra steps will help you build an incredibly fast, secure, and highly profitable website that your clients will love to use [1].



