DEV Community

Risky Egbuna
Risky Egbuna

Posted on

We Built an Agency Website in 7 Days: Marpixel WordPress Theme Review

7 Days with Marpixel: A Raw Developer Diary of Building a Fast Agency Site


Last week, my long-term client Sarah called me. She runs a local digital marketing agency in Boston called Apex Digital. Her website was a complete mess. It was built years ago with a heavy, bloated page builder, running 45 different active plugins, and taking nearly six seconds to load on a standard mobile connection. Her Google PageSpeed Insights score was a painful 22 out of 100 on mobile devices. Leads were dropping, search engine rankings were sinking, and she was losing real money every single day.

She gave me a simple but brutal challenge: "I need a fresh, modern, fast website that ranks well, looks professional, and is easy for my team to maintain. I need it done in seven days."

As a developer with over ten years of experience rebuilding clunky WordPress sites, I knew we could not just patch up her old site. We needed a clean slate. I decided to build a fresh staging environment, pick a highly targeted theme, and optimize the hell out of it from day one. After looking at several options, I decided to go with Marpixel - Digital Marketing Agency WordPress Theme for our design foundation. It had the modern, tech-focused layout she wanted, but I needed to see how it would perform under real developer scrutiny.

This is my raw, day-by-day diary of how I turned a bloated, slow agency site into a lightning-fast, SEO-optimized lead machine in exactly one week using this theme.


Day 1: Setting up the Sandbox and First Impressions

A fast website starts with the server. I did not want to host this on cheap shared hosting. I spun up a fresh, clean VPS running Nginx, MariaDB, and PHP 8.2. I wanted to make sure we had a modern environment with HTTP/2 and fast caching right out of the gate.

Instead of clicking around the WordPress dashboard, I always use WP-CLI to speed up my workflow. It keeps things clean and lets me avoid installing useless default themes and plugins that WordPress throws at you during a standard install. Here is the quick set of commands I used in my terminal to spin up the clean core:

# Download the latest WordPress core
wp core download --path=public_html

# Create the config file
wp config create --dbname=marpixel_db --dbuser=marpixel_usr --dbpass=my_secure_password --path=public_html

# Run the installation
wp core install --url=https://staging.apexagency.com --title="Apex Digital" --admin_user=admin_dev --admin_email=admin@apexagency.com --admin_password=secure_dev_pass --path=public_html

# Clean out the default themes and plugins
wp theme delete twentytwentytwo twentytwentythree twentytwentyfour --path=public_html
wp plugin delete hello akismet --path=public_html
Enter fullscreen mode Exit fullscreen mode

Once the clean install was ready, I uploaded the zip file for the theme. The theme file was surprisingly lightweight compared to some of the massive multi-purpose themes I have worked with in the past. This was a good sign. Heavy themes usually mean hundreds of unused scripts loading on every single page.

I installed the theme and created a child theme immediately. Never build on a parent theme directly. If the theme developer releases an update to fix a security bug, all your custom code will be wiped out. I set up a basic style.css and functions.php inside my child theme folder and activated it. By the end of Day 1, we had a blank canvas ready for layout customization and content migration.


Day 2: The First Technical Friction and How I Fixed It

On Day 2, I started exploring the theme's core assets and custom layouts. The layout looked great, and the block patterns were clean. However, I ran into my first real technical friction point. Like many modern themes, this theme registers custom image sizes to ensure portfolio and blog grids look neat.

But when I ran my first asset test, I noticed the theme was generating several massive, uncompressed thumbnail sizes that we did not need for our design. These extra image crops were bloating our server's disk space. Worse, the default portfolio loop was loading a massive 1200px wide image into a tiny 350px container on mobile viewports. This caused a major flag in our performance report.

Additionally, the default custom post type for the portfolio used a generic rewrite slug that clashed with a legacy redirect system my client had been using for years. I needed a way to control the image sizes and filter the registration arguments of the custom post types without hacking the parent theme's core files.

To fix this, I wrote a custom PHP script in our child theme's functions.php. This script does two things: it removes the redundant image sizes that we did not need, registers a highly optimized custom size for our portfolio grids, and modifies the registration parameters of the custom post types to use our preferred URL structure. Here is the exact code I used:

<?php
/**
 * Marpixel Child Theme Functions
 * Written on Day 2 of the restructuring diary.
 */

// 1. Optimize image crop sizes to prevent asset bloat
function apex_optimize_image_sizes() {
    // Remove default large sizes we don't use in grids
    remove_image_size('medium_large');

    // Add our highly optimized custom size for the portfolio grid
    add_image_size('apex-portfolio-grid', 400, 280, true);
}
add_action('after_setup_theme', 'apex_optimize_image_sizes', 11);

// 2. Adjust custom post type arguments for SEO and redirect compatibility
function apex_modify_portfolio_cpt_args($args, $post_type) {
    if ('portfolio' === $post_type) {
        // Change the slug to fit our legacy structure and enable better rewrite rules
        $args['rewrite'] = array(
            'slug'       => 'case-studies',
            'with_front' => false,
            'pages'      => true,
            'feeds'      => false,
        );
        // Ensure support for excerpt is enabled for better meta description control
        $args['supports'][] = 'excerpt';
    }
    return $args;
}
add_filter('register_post_type_args', 'apex_modify_portfolio_cpt_args', 20, 2);
?>
Enter fullscreen mode Exit fullscreen mode

After implementing this code, I used the WP-CLI command wp media regenerate --yes to rebuild our entire media library. This immediately cut our uploaded image sizes down, shrunk the page weight on grid layouts, and corrected our URL structure for our portfolio pages. The mobile viewport started loading the fast, optimized 400px image instead of the massive original file. Friction solved.


Day 3: Speed Optimization, Nginx Caching, and Critical CSS

Today was all about performance. A modern agency theme 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. 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. It reduces the Time to First Byte (TTFB) from 800 milliseconds down to less than 50 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=WORDPRESS: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 staging.apexagency.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.2-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 WORDPRESS;
        fastcgi_cache_valid 200 301 302 1d;
        add_header X-FastCGI-Cache $upstream_cache_status;
    }
}
Enter fullscreen mode Exit fullscreen mode

Second, I needed to deal with Critical CSS. When a browser loads a webpage, it downloads the entire stylesheet before rendering the page. This causes a delay. To fix this, I extracted the minimal CSS required to render the top fold of our homepage. I wrote a small PHP script in our child theme to print this critical CSS directly into the <head> of our site, and then deferred the rest of our main stylesheets using a standard JavaScript loader. This way, the page renders instantly, and the remaining styles load in the background.

<?php
// Inject Critical CSS and defer main theme styles
function apex_inject_critical_css() {
    if (is_front_page()) {
        echo '<style type="text/css">';
        // Minimal critical path CSS for the hero section
        echo 'body{margin:0;font-family:sans-serif;color:#1e1e1e;background-color:#fff;}';
        echo '.hero-section{padding:80px 0;background-color:#0b0c10;}';
        echo '.hero-title{font-size:2.5rem;line-height:1.2;font-weight:700;color:#fff;}';
        echo '.hero-subtitle{font-size:1.1rem;margin-top:15px;color:#c5c6c7;}';
        echo '</style>';
    }
}
add_action('wp_head', 'apex_inject_critical_css', 5);

// Defer the main stylesheet to improve First Contentful Paint
function apex_defer_style_loading($html, $handle, $href, $media) {
    // Only defer on the front page to keep it safe and isolated
    if (is_front_page() && 'parent-theme-style' === $handle) {
        return "<link rel='stylesheet' id='$handle' href='$href' media='print' onload=\"this.media='$media'\">\n";
    }
    return $html;
}
add_filter('style_loader_tag', 'apex_defer_style_loading', 10, 4);
?>
Enter fullscreen mode Exit fullscreen mode

By combining Nginx memory caching and this smart stylesheet deferral, we saw our homepage load speed drop from 1.8 seconds down to a blistering 240 milliseconds on our local staging speed tests. That is faster than the blink of an eye.


Day 4: Content Migration and Eliminating Icon Font Bloat

By Day 4, the foundation was solid, and the site was fast. Now it was time to rebuild the core service pages. The theme includes excellent built-in layout patterns designed specifically for agency service grids, team showcases, and case studies. I started moving the content over from the old, slow site.

While building the service sections, I noticed that the template loaded several web font files to show simple icons (like checkmarks, email icons, and phone symbols). These icon fonts, such as FontAwesome, weigh over 1.2MB and take a long time to download, especially on slower mobile networks. Why load a massive font package when we only need five or six simple icons on our main page?

I decided to block the loading of these icon fonts and write a fast, clean PHP helper function in our child theme to render local SVG files directly in our templates. This technique prevents external requests and makes sure the icons load instantly with zero delay.

First, I created an assets/svg/ folder in our child theme and downloaded the raw SVG files for the specific icons we needed. Then, I registered this simple helper function:

<?php
/**
 * Inline SVG Helper Function
 * Renders local vector graphics instead of bulky web fonts.
 */
function apex_get_svg($icon_name) {
    $file_path = get_stylesheet_directory() . '/assets/svg/' . $icon_name . '.svg';

    if (file_exists($file_path)) {
        // Read and output the clean SVG code
        return file_get_contents($file_path);
    }
    return '';
}
?>
Enter fullscreen mode Exit fullscreen mode

Instead of relying on a classic HTML icon tag like <i class="fa fa-envelope"></i>, I updated our child theme templates to pull the SVG directly: <?php echo apex_get_svg('envelope'); ?>. This small change removed another unnecessary request from our waterfall chart and gave us complete control over our icon styling using clean, lightweight CSS.


Day 5: White-Hat SEO Tweaks and Schema Markup

As a white-hat SEO expert, I know that Google does not just care about how fast your site loads; it cares about how well-structured your content is. I spent Day 5 auditing the theme's default HTML output. I wanted to make sure our headings were perfect and that we were feeding clean, structured data to search engine crawlers.

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.

I copied the theme's archive loop file into our child theme folder and adjusted the markup. I changed the post titles from <h1> to <h2> and adjusted the styling to match. This kept the page look identical while giving search engines a clear, logical structure.

Next, I wanted to inject structured JSON-LD schema markup for Sarah's agency. Structured data helps Google understand who you are, what you do, and where you are located. I didn't want to use a bulky, heavy plugin just to add a block of JSON. Instead, I wrote a fast, clean function to output the schema markup directly into our footer:

<?php
/**
 * Inject local business schema markup for trust and SEO authority.
 */
function apex_inject_local_business_schema() {
    // Only output this JSON-LD schema on the homepage
    if (is_front_page()) {
        $schema = array(
            "@context"    => "https://schema.org",
            "@type"       => "ProfessionalService",
            "name"        => "Apex Digital Boston",
            "image"       => "https://staging.apexagency.com/wp-content/uploads/logo.png",
            "@id"         => "https://staging.apexagency.com/#organization",
            "url"         => "https://staging.apexagency.com",
            "telephone"   => "+1-617-555-0199",
            "priceRange"  => "$$",
            "address"     => array(
                "@type"           => "PostalAddress",
                "streetAddress"   => "100 Summer Street",
                "addressLocality" => "Boston",
                "addressRegion"   => "MA",
                "postalCode"      => "02110",
                "addressCountry"  => "US"
            ),
            "openingHoursSpecification" => array(
                "@type"     => "OpeningHoursSpecification",
                "dayOfWeek" => array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"),
                "opens"     => "09:00",
                "closes"    => "18:00"
            )
        );

        echo "\n" . '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
    }
}
add_action('wp_footer', 'apex_inject_local_business_schema', 100);
?>
Enter fullscreen mode Exit fullscreen mode

Google picked up this clean schema markup immediately when I ran it through the Rich Results Test. This is pure white-hat SEO: fast, clean, compliant, and zero performance cost.


Day 6: Mobile Polish and Touch Target Adjustments

Today was dedicated to real-world user experience (UX) testing on mobile devices. I loaded the staging site on my personal iPhone 13 and an older, cheap Android test device. While the theme looked stunning on my 27-inch desktop monitor, mobile users interact with their thumbs, not a precise mouse pointer. This is a critical area for Google's page experience signals.

I noticed that the dropdown menu icon in the mobile navigation was slightly too close to the main menu item link. On smaller screens, trying to click the dropdown arrow would occasionally trigger the parent menu item link instead. This was a classic "touch targets are too close together" issue, which Google flags as a mobile usability problem.

I opened my code editor and added custom mobile overrides in our child theme's style.css file. I expanded the clickable padding around the sub-menu toggle element and repositioned it to ensure visitors with larger fingers could navigate the site easily without getting frustrated.

/* Mobile Menu Touch Target Adjustments */
@media (max-width: 991px) {
    .mobile-menu-container .menu-item-has-children .sub-menu-toggle {
        display: inline-block;
        padding: 15px !important; /* Generous touch area */
        position: absolute;
        right: 5px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 10;
        cursor: pointer;
    }

    .mobile-menu-container .menu-item a {
        padding-top: 12px !important;
        padding-bottom: 12px !important;
        font-size: 1.1rem; /* Highly readable font size */
    }
}
Enter fullscreen mode Exit fullscreen mode

This simple adjustment resolved the touch friction. The mobile menu became extremely easy to navigate, and our mobile viewport testing in Chrome DevTools showed zero overlapping elements.


Day 7: The Final Launch and Performance Verdict

The staging site was fully optimized, the content was clean, the URL structure was perfect, and the mobile experience was seamless. It was time to go live. I ran a quick database cleanup using WP-CLI to delete post revisions and clear out transient database values that had built up during development:

# Clean database transients
wp transient delete --all --path=public_html

# Clean post revisions to keep our database lightweight
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision'" --path=public_html
Enter fullscreen mode Exit fullscreen mode

I pointed the production domain to our new optimized VPS server and ran our final PageSpeed tests. The results were spectacular. On mobile, our performance score jumped from the original 22 up to a 94. On desktop, we hit a near-perfect score of 99. The First Contentful Paint was down to 0.8 seconds, and the Largest Contentful Paint was well under the 2.5-second threshold required by Google's Core Web Vitals.

Sarah was absolutely thrilled. Her team had a fast, modern platform they could manage easily, and she was already noticing more direct form submissions from mobile visitors who no longer had to wait ages for her old site to load.


Honest Developer Verdict: Pros and Cons of Marpixel

After spending a full week working with this theme, I want to share an honest, realistic breakdown of what I liked and what fell short. No theme is perfect, and you should always know what you are getting into before you start a project.

What I Liked (The Pros)

  • Well-Written Markup: Unlike many modern themes that load massive wrapper layers, this theme features lightweight CSS files and a clean, direct HTML layout structure that makes performance optimization much easier.
  • Niche Focus: The pre-designed sections and patterns are built specifically for marketing agencies. We did not have to spend days creating custom layouts for services, team members, and case studies. They were already clean and beautiful.
  • Asset Management: The theme developer did a great job avoiding script duplication. It does not try to load multiple redundant JS libraries on page loads, which is a common cause of poor mobile scores.

What Needs Work (The Cons)

  • Basic Documentation: The setup documentation is a bit basic. If you are an absolute beginner who has never touched a line of code, you might find some of the advanced template customization tutorials a bit brief.
  • Excessive Image Crops: As I detailed on Day 2, the theme registers a few default image crop sizes that can inflate your media folder and load larger files than necessary if you do not use hooks to control them.

My Final Recommendation

If you are looking for a solid, modern, and clean foundation for a digital marketing or creative agency website, this theme is an exceptional option. It is beautifully designed, lightweight, and built in a way that respects modern development standards. However, if you want 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. With just a small amount of technical work, you can turn this theme into an incredibly fast, secure, and profitable lead-generation engine for your business.

Top comments (0)