How to build a WordPress developer portfolio in 2026

How to build a WordPress developer portfolio in 2026

Last verified: October 12, 2026
16 min read
Tutorial

Many freelancers and agencies treat the portfolio section as a gallery: “here is a pizza shop website, pretty, right?”. A client does not buy a website, they buy the solution to a problem. A portfolio that does not show the problem, the technical decision and the result leaves the client without the information they need to choose you.

#Why a WordPress developer portfolio matters

For a WordPress developer, the portfolio is proof that you can do what you claim, and a way to show how you think, which a CV does not convey. There are plenty of WordPress freelancers on offer, so what sets you apart is the quality of what you show, not the number of projects.

#What clients look for in a WordPress freelancer

  • Solutions, not technologies: the client does not care that you used React, they care that you solved their kind of problem.
  • Metrics and results: concrete numbers with a source, not vague phrases like “I improved performance”.
  • Thought process: how you arrived at the solution and which alternatives you ruled out.

#How to write a WordPress portfolio case study

Instead of a screenshot and a link, describe the process. A good portfolio is a collection of case studies, and each one answers three questions.

#Challenge: the client’s problem

Do not write “I built a website”. Write the specific problem. The examples below are illustrative, not from real projects:

  • “A store with 10,000 products took 8 seconds to load and lost carts along the way.”
  • “The site used a huge amount of monthly bandwidth because of unoptimized images.”
  • “The client lost mobile conversions because the site was not responsive.”

Why it works: the reader recognizes the problem. If they have a similar one, they know right away that you understand their situation.

#Solution: what you did and why

Explain not only what you did, but why you chose that solution over another:

“Instead of standard WooCommerce, I chose headless WordPress with Next.js because the client needed:

  • a load time under 1 s (Core Web Vitals),
  • integration with the external API of their ERP,
  • the ability to scale to 100,000 products.

Solution: WordPress as a headless CMS, a Next.js frontend, Redis cache and the Cloudflare CDN.”

This shows that you do not copy templates but decide with technical judgement. It also helps to add what you did not choose and why: a sentence like “I ruled out a caching plugin because the catalog changed every hour” says more than a list of tools.

#Result: numbers with a source

This is the most important part. Show the state before and after, and say where each figure comes from:

  • Google Analytics: conversions, bounce rate, cart abandonment.
  • PageSpeed Insights (Core Web Vitals): LCP, INP, CLS.
  • GTmetrix: load time.
  • Server logs: data transfer and database queries.

A figure without a source does not survive the first question from a technical client. If you cannot prove it, do not publish it.

#Case study example with an invented client

Project: online store for a furniture manufacturer. The figures in this example are invented to illustrate the format and do not come from a real project.

Challenge. The client ran a WooCommerce store with 8,000 products. The site loaded in 6 seconds, with three consequences:

  • 45% cart abandonment,
  • a conversion drop from 3.2% to 1.8% over a year,
  • indexing problems and Core Web Vitals in red.

Solution.

  1. Migration to headless WordPress: WordPress as the CMS and Next.js as the frontend.
  2. Image optimization: AVIF, lazy loading and responsive images.
  3. Caching strategy: Redis for products and Cloudflare for static assets.
  4. Database optimization: indexes and WP_Query queries.
  5. CDN with automatic CSS and JS minification.

Stack: headless WordPress, Next.js, Redis, Cloudflare, WooCommerce REST API.

Result (illustrative):

  • Load time: from 6 s to 0.8 s.
  • Conversion: from 1.8% to 3.9%.
  • Cart abandonment: from 45% to 12%.
  • Core Web Vitals: all green.

A good case study also states how long the project took and who took part, because it gives the client a sense of scale. If you worked alone, say so; if you worked with a designer and another developer, name them by role.

#What code to show on GitHub

If you are looking for a job at a software company, the portfolio has to show code quality.

#How to publish code from private projects

Even if the project is private, you can create public samples:

  1. Snippets from projects: extract the best pieces and remove any client data.
  2. Open source contributions: to WordPress Core or to plugins.
  3. Side projects: small tools that show your skills.

Before you publish a snippet, check that it contains no keys, internal paths or client names.

#Custom WordPress hooks

This example limits and filters the main query of a store:

/**
 * Limit and filter the WooCommerce catalog query
 *
 * @param WP_Query $query
 */
add_action('pre_get_posts', function ($query) {
    if (!is_admin() && $query->is_main_query() && is_shop()) {
        $query->set('posts_per_page', 24);
        $query->set('meta_query', [
            [
                'key'     => '_stock_status',
                'value'   => 'instock',
                'compare' => '=',
            ],
        ]);
    }
});

It shows that you know WordPress hooks, think about query performance and document your code. One detail that counts: do not add no_found_rows to a paginated listing, because it breaks the page count.

#Modern PHP (8.1 or newer)

class ProductCache
{
    public function __construct(
        private Redis $redis,
        private int $ttl = 3600
    ) {}

    public function getProductData(int $productId): ?array
    {
        $cacheKey = "product:{$productId}";

        if ($cached = $this->redis->get($cacheKey)) {
            return json_decode($cached, true);
        }

        $product = wc_get_product($productId);
        if (!$product) {
            return null;
        }

        $data = ['id' => $productId, 'name' => $product->get_name(), 'price' => $product->get_price()];
        $this->redis->setex($cacheKey, $this->ttl, json_encode($data));

        return $data;
    }
}

It shows typed properties, constructor property promotion, dependency injection and a caching pattern. Cache only the data you need, not whole WooCommerce objects.

#Gutenberg block development

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';

registerBlockType('my-prefix/portfolio-item', {
    edit: ({ attributes }) => {
        const blockProps = useBlockProps();
        return (
            <div {...blockProps}>
                <h3>{attributes.title}</h3>
                <p>{attributes.description}</p>
            </div>
        );
    },
    save: () => null, // Server-side rendering
});

It shows knowledge of the block API, React inside WordPress and server-side rendering. To go further, the guide to Gutenberg blocks, patterns and Full Site Editing explains how to structure them.

#Which tech stack is worth showing

Essential in 2026:

  • Gutenberg (FSE): Full Site Editing and block development.
  • React and Next.js: headless WordPress.
  • Composer: dependency management.
  • WP-CLI: automation and deployment.
  • Docker: local environment; there is a guide to WordPress development with Docker.
  • Git: version control, and not just push and pull but a branching strategy.

Extra points: TypeScript, GraphQL, tests (PHPUnit, Jest, Cypress) and CI/CD with GitHub Actions or GitLab CI.

#What not to show in a developer portfolio

  1. Projects built on ready-made ThemeForest themes, unless you customized them heavily. In that case, show what you changed.
  2. Code without comments, even if it seems obvious to you.
  3. Outdated practices, such as direct SQL queries instead of WP_Query.
  4. Hardcoded values: show that you use constants, filters and options.

#How to build a portfolio in WordPress with ACF

You do not need complex plugins: WordPress ships with what you need.

#How to register a portfolio custom post type

function my_theme_register_portfolio_cpt() {
    register_post_type('portfolio', [
        'labels' => [
            'name' => 'Portfolio',
            'singular_name' => 'Project',
        ],
        'public' => true,
        'has_archive' => true,
        'supports' => ['title', 'editor', 'thumbnail', 'excerpt'],
        'rewrite' => ['slug' => 'portfolio'],
        'show_in_rest' => true,
    ]);
}
add_action('init', 'my_theme_register_portfolio_cpt');

#ACF fields for portfolio projects

acf_add_local_field_group([
    'key' => 'portfolio_fields',
    'title' => 'Portfolio details',
    'fields' => [
        ['key' => 'client_name', 'name' => 'client_name', 'label' => 'Client name', 'type' => 'text'],
        ['key' => 'project_year', 'name' => 'project_year', 'label' => 'Project year', 'type' => 'number'],
        [
            'key' => 'tech_stack',
            'name' => 'tech_stack',
            'label' => 'Tech stack',
            'type' => 'checkbox',
            'choices' => [
                'wordpress' => 'WordPress',
                'react' => 'React',
                'nextjs' => 'Next.js',
                'woocommerce' => 'WooCommerce',
            ],
        ],
        [
            'key' => 'metrics',
            'name' => 'metrics',
            'label' => 'Metrics (before and after)',
            'type' => 'repeater',
            'sub_fields' => [
                ['key' => 'metric_name', 'name' => 'metric_name', 'label' => 'Metric', 'type' => 'text'],
                ['key' => 'before_value', 'name' => 'before_value', 'label' => 'Before', 'type' => 'text'],
                ['key' => 'after_value', 'name' => 'after_value', 'label' => 'After', 'type' => 'text'],
            ],
        ],
    ],
    'location' => [[[
        'param' => 'post_type',
        'operator' => '==',
        'value' => 'portfolio',
    ]]],
]);

This gives every project the same fields, so you can show the before and after comparison with the same structure in every case study. Data you do not want on the editing screen, such as internal notes or the source of each metric, goes into meta fields with an underscore prefix (_metrics_source): WordPress hides them from the custom fields panel.

#Server-rendered block for the metrics

Instead of a page builder, you can render the metrics with your own block and reuse it in every case study:

// Block: portfolio metrics
register_block_type('my-prefix/portfolio-metrics', [
    'render_callback' => function ($attributes) {
        $metrics = get_field('metrics');
        if (!$metrics) {
            return '';
        }

        ob_start();
        ?>
        <div class="portfolio-metrics">
            <?php foreach ($metrics as $metric) : ?>
                <div class="metric-item">
                    <span class="metric-name"><?php echo esc_html($metric['metric_name']); ?></span>
                    <span class="metric-before"><?php echo esc_html($metric['before_value']); ?></span>
                    <span class="metric-separator">to</span>
                    <span class="metric-after"><?php echo esc_html($metric['after_value']); ?></span>
                </div>
            <?php endforeach; ?>
        </div>
        <?php
        return ob_get_clean();
    },
]);

#single-portfolio.php template for each project

// single-portfolio.php
get_header();
?>

<article class="portfolio-case-study">
    <header>
        <h1><?php the_title(); ?></h1>
        <p>
            <?php if ($client = get_field('client_name')) : ?>
                Client: <?php echo esc_html($client); ?>
            <?php endif; ?>
            Year: <?php echo esc_html(get_field('project_year')); ?>
        </p>
    </header>

    <section class="solution">
        <h2>Solution</h2>
        <?php the_content(); ?>
    </section>

    <section class="results">
        <h2>Results</h2>
        <?php foreach ((array) get_field('metrics') as $metric) : ?>
            <p>
                <?php echo esc_html($metric['metric_name']); ?>:
                <?php echo esc_html($metric['before_value']); ?> to
                <?php echo esc_html($metric['after_value']); ?>
            </p>
        <?php endforeach; ?>
    </section>
</article>

<?php get_footer();

Always escape with esc_html(): the portfolio is your code and gets judged as such.

#How to rank a developer portfolio in Google

The portfolio is not only for people: Google reads it too.

#Schema.org JSON-LD markup for the portfolio

function my_theme_portfolio_schema() {
    $schema = [
        '@context' => 'https://schema.org',
        '@type' => 'CreativeWork',
        'name' => get_the_title(),
        'description' => get_the_excerpt(),
        'creator' => [
            '@type' => 'Person',
            'name' => 'Your name',
        ],
        'datePublished' => get_the_date('c'),
        'url' => get_permalink(),
    ];

    if ($client = get_field('client_name')) {
        $schema['sourceOrganization'] = [
            '@type' => 'Organization',
            'name' => $client,
        ];
    }

    return $schema;
}

The client name only enters the markup when the field has a value, so a client who prefers anonymity appears neither on the page nor in the structured data.

#How to optimize portfolio images

  1. Lazy loading: for everything except the first visible image.
  2. Modern formats: WebP or AVIF; the guide to WordPress image optimisation explains the process.
  3. Responsive images: different sizes for different devices.
  4. Descriptive alt text: “metrics dashboard before and after the migration”, not “portfolio-image-1”.

#What the best developer portfolios have in common

  1. Concrete metrics: not “I improved performance” but “load time dropped from 5 s to 0.8 s”, with the source.
  2. Thought process: how the solution was reached and what was ruled out.
  3. Code in context: not just a GitHub link, but an explanation of the decisions.
  4. Visual material: architecture diagrams and before and after screenshots.
  5. Client feedback: one sentence signed by the client, with their permission, carries more weight than any adjective of your own.

#How to show private or NDA projects in a portfolio

Many of the best projects cannot be shown as they are: the code belongs to the client or the contract forbids naming them. A case study is still possible.

  • Client name: the ACF field is optional, and the CreativeWork markup only adds the organization when it has a value. Describe the sector, for example “furniture manufacturer”, and leave the name empty.
  • Code: extract snippets into a public repository. A hook that optimizes WP_Query or a caching class in PHP 8.1 shows judgement without exposing the project.
  • Metrics: if you did not record them during the work, recover them from Google Analytics, PageSpeed Insights, GTmetrix or the logs. If there is no reliable figure, describe the challenge and the technical decision, and do not publish a number you could not defend in front of the client.
  • Permission: ask what you may publish before you write the case study, not after.
  • Your own archive: keep the before and after figures, the screenshots and the client feedback for each project in your files, so you can prove them when someone questions them.

A case study without a logo, with the problem, the solution and the reasoning well explained, still answers the question that counts: why the client should choose you.

#WordPress.org profile as public proof of contribution

You write a case study yourself. The WordPress.org profile (profiles.wordpress.org) is generated by the platform, which is why a technical client reads it as an independent record. Link to it from the portfolio next to your GitHub profile.

What carries the most weight on that profile are the badges. The Meta team handbook distinguishes two types: contributor badges, generally given to anyone who has contributed to a team, and team badges, given to people active in it. Each team sets its own criteria, and several badges are assigned automatically:

BadgeHow you get it, according to the Meta handbook
Core ContributorAutomatically, though not instantly, when you receive props in a core commit
Plugin DeveloperAutomatically, when you have a plugin in the directory
Theme DeveloperAutomatically, when you have a theme in the directory
WordCamp SpeakerAutomatically, based on speaker status on WordCamp.org, with a WordPress.org username

The rest are assigned by hand by each team. The criteria vary: the Openverse team handbook, for example, asks you to meet at least one of several conditions, among them opening five or more valid issues, getting a substantial pull request merged or translating 25 strings. A Plugin Developer badge does not say whether the plugin is good, but it does say that it passed someone else’s review, and that is more than a screenshot proves.

#What is Five for the Future and how it counts in a portfolio

Five for the Future started with a post by Matt Mullenweg on 30 September 2014. The sentence behind the program’s name says that organizations that want to grow the WordPress pie, not just their own slice, “should dedicate 5% of their people to working on something to do with core”, be it development, documentation, security, support forums, theme reviews, training, testing or translation (Matt Mullenweg, “Five for the Future”).

Today the program lives at wordpress.org/five-for-the-future. Both organizations and individuals can pledge: organizations appear on the pledges page, and individual contributors are shown with their name, a photo, a short bio and the sponsoring organization, if there is one. For a freelancer, a pledge of weekly hours to a specific team (Core, Polyglots, Training, Documentation) is a verifiable line in the portfolio. For an agency, appearing in the list of organizations is a way to show that it contributes to the project it makes its living from.

#How to publish a plugin in the WordPress.org directory

A plugin approved for the directory is a code sample reviewed by third parties and used by real people. The plugin handbook describes the process:

  1. Register on WordPress.org with an email address you check; if you submit on behalf of a company, use an official company address.
  2. Submit a short description and a complete zip of the plugin, the same one you would install by hand from the dashboard.
  3. Wait for the review: the team reviews the code within 14 business days and contacts you if it finds problems.
  4. After approval you get access to a Subversion repository; the plugin appears in the directory once you upload the code and the readme via SVN.

Two details matter for the portfolio. The plugin URL cannot be changed after submission, although the display name can. And every plugin in the directory has its own support forum, so your answers to users are public and become part of what a client can read about you.

The detailed plugin guidelines number 18. The ones behind most rejections: a GPL or compatible license (guideline 1), code that is mostly human-readable (4), no functionality locked behind payment (5), no contacting external servers without explicit consent (7) and no third-party trademarks as the first term of the slug (17). If your plugin meets them, you already have a technical argument for the case study.

#GitHub profile README and pinned repositories

GitHub’s documentation sets four conditions for a README to appear on your profile: a repository with the same name as your username, public, with a README.md file in the root, and with some content. Use it as an index: what you do, a link to the portfolio, a link to your WordPress.org profile and the two or three repositories that represent you best.

You can also pin to your profile up to six repositories and gists in total. Pin the ones that match your case studies, such as the directory plugin, the repository of anonymized client snippets or the block theme, and not forks without changes.

#Learn WordPress to fill gaps in your stack

If, while preparing the portfolio, you notice something from the stack list is missing, Learn WordPress organizes its content into three pathways (using, developing and designing with WordPress), with courses, lessons and live workshops. In October 2026 the Beginner WordPress Developer course is listed at 9 hours and 59 lessons, and Intermediate Theme Developer at 8 hours and 32 lessons. A finished course does not replace a case study; what goes into the portfolio is the block or theme you build with what you learned.

#Where to start building your portfolio

  1. Choose 5 to 7 projects with a result you can measure.
  2. Gather the data: metrics with a source, screenshots and, if the client allows it, a sentence from them.
  3. Write the first case study with the challenge, solution and result structure. Budget about two hours.
  4. Prepare the code samples on GitHub, without client data and with PHP 8.1 or newer.
  5. Set up the CPT with ACF and publish the case studies in the same format.
  6. Review the GitHub code whenever you add a project: a repository full of old syntax weakens the case study that links to it.

The portfolio is not a CV: every project has to answer why the client should choose you. For a published case study with this structure, see the WooCommerce optimization case study.

Next step

Turn the article into an actual implementation

This block strengthens internal linking and gives readers the most relevant next move instead of leaving them at a dead end.

Want this implemented on your site?

If you want to convert the article into a working site improvement, redesign, or build plan, I can define the scope and implement it.

Related cluster

Explore other WordPress services and knowledge base

Strengthen your business with professional technical support in key areas of the WordPress ecosystem.

Frequently asked questions

Practical answers to apply the topic in real execution.

What matters more in a WordPress portfolio, screenshots or case studies?#
Case studies. A client wants to understand how you think, how you solved a problem and what measurable result you got, not just look at nice images.
How many projects should a WordPress portfolio include?#
Between 5 and 7 well-documented projects, each with its problem, solution and metrics, explain more than dozens of screenshots without context.
Do I need to code to have a good WordPress portfolio?#
For a design or project management profile it is not essential. If you present yourself as a developer, visible code on GitHub with hooks, modern PHP and Gutenberg blocks is the most direct proof of your level.
How long does it take to build a WordPress developer portfolio?#
Plan around two hours per case study and a couple of days end to end if you start from scratch. Most of the work is collecting metrics, screenshots and client feedback; the WordPress and ACF setup is the smallest part.
What is the minimum stack needed for a portfolio site?#
WordPress with a custom post type, ACF for structured fields and a public GitHub account for code samples. Use PHP 8.1 or newer so the snippets do not look outdated.
What mistakes are common when presenting a portfolio?#
Showing only screenshots without a challenge, a solution or a measurable result, so nobody can tell whether you solved a real problem. And publishing client data without permission.

Need an FAQ tailored to your industry and market? We can build one aligned with your business goals.

Let’s discuss

Related Articles

Remote work in IT 2026: 60 percent at home, but nobody talks about it

Just Join IT surveys for 2023, 2024 and 2025 show that around 60 percent of Polish IT specialists work fully remote and only around 7 percent go to the office every day. A polemic against the "return to office" narrative, built on job board data, Eurostat and the Polish Labour Code, and what it means for the western outsourcing buyer.