Portfolio

E-commerce Development: pluginfinance.com

pluginfinance.com is a modern, highly scalable WordPress-based service dedicated to showcasing and distributing financial plugins. The project was designed w...

#Logotypes#Websites
E-commerce Development: pluginfinance.com

#The sale is the beginning, not the end

pluginfinance.com presents and distributes plugins for the financial sector. The build started in 2012, covered the visual identity as well as the site, and the first version took about six weeks. The platform has been maintained and modernised since, which is why it now runs on PHP 8 and MySQL 8, with WordPress as the content and commerce layer and a React front end talking to it over REST and GraphQL.

What makes a software shop different from a shop selling objects is that the transaction does not close anything. A customer who buys a plugin expects updates for as long as the licence runs, which means the shop keeps a live relationship with every installation it ever sold to. The licence key issued after payment is the start of that relationship, not a receipt for it.

The practical consequence arrives in the traffic graph. The site is queried not only by people with browsers but by hundreds of WordPress installations checking for updates on their own schedule, at hours nobody chose. That traffic is invisible in visit statistics and extremely visible in server load if nobody planned for it. So the licence and version endpoint answers as briefly as possible, reads from Redis and never boots the full page lifecycle. The update file itself is served from the edge, because it is a static file rather than the result of a database query. Splitting the permission check from the file delivery is the core of it: the check must be cheap and exact, the transfer is expensive and belongs as far from the application as possible.

One more rule sits underneath that and it is a legal requirement expressed in code. An expired licence must not disable an installed plugin. The customer paid for software that keeps working; what expiry withdraws is the right to updates and support, not the right to use. Licence state and plugin state therefore have to be two independent values. Conflate them and the first late renewal leaves a customer with a disabled module in production and an outage the shop caused.

There is no results table in this case study. Sales figures belong to the client, not to a portfolio entry on our site. What can be shown honestly is what was decided and why.

#A product page that is really a spec sheet

A finance plugin is bought on parameters, not on a photograph. Buyers want to know which WordPress and PHP versions it supports, what external dependencies it drags in, whether it works in a multilingual setup, what exactly it does with payment data, and what the support path looks like after purchase. None of that belongs in a paragraph of prose, because all of it has to be filterable and comparable.

Products are therefore described by dedicated content types and custom fields built on Advanced Custom Fields. A technical parameter is a field, not a sentence. The obvious benefit is filtering and sorting. The less obvious one shows up in maintenance: when WordPress ships a major release, updating compatibility across the whole catalogue is one operation on a field, rather than reading through several dozen descriptions hunting for the sentence that mentions a version. A catalogue that keeps compatibility in prose is lying about half its entries within two years, and nobody notices.

Comparison tables depend on that discipline more than anything else. A buyer evaluating financial tooling usually narrows to two or three candidates and wants them side by side, attribute against attribute. A comparison is only as good as field completeness: if half the products have an empty compatibility field, the table misleads more effectively than it helps. So the fields that drive comparison are required at publication rather than optional. That is an editorial rule enforced technically, and it is the only thing that keeps a comparison meaningful after two years of adding products.

Reviews, case studies and expert articles are separate content types, and so is product documentation. Documentation has versions: the installation guide for last year’s release cannot vanish the moment a new one ships, because some customers deliberately stay on an older branch. Keeping documentation as child pages of a product looks tidy until the first significant API change, when two versions of the same instruction have to be visible at once.

#Headless, and the honest cost of it

The interface is a browser-side application with WordPress acting as the content and commerce back end. That choice had a specific justification here, and we do not recommend it reflexively for every shop.

The justification is multi-dimensional filtering. Buyers narrow the catalogue by integration type, by version compatibility, by licence model and by several other attributes, changing their mind along the way. In a classic model every filter change is a page reload and a full server-side render. On a catalogue with rich attributes that means a dozen or more database queries per checkbox click. A separated front end fetches the result list only, not the whole view.

The costs are real and worth naming. Content generated in the browser can be harder for crawlers to see, so the pages that must earn search traffic, meaning product pages and editorial material, are rendered server side and delivered as finished HTML. Only the catalogue interaction is client side. The second cost is the API surface itself, which becomes another boundary to maintain and secure. GraphQL solves part of the problem by letting one query fetch exactly the fields a view needs, instead of three REST calls each returning too much, but it needs careful limits on query complexity. A public GraphQL endpoint with no depth limit is an invitation to exhaust a server with a single request.

#Where the edge cache has to stop

Redis handles the object cache and sessions, Cloudflare sits at the edge, and there is page caching on the server as well. Three layers sound excessive until you write down which kind of request lands where.

A shop splits traffic into two unequal parts. Catalogue pages and editorial material are identical for every visitor, so they can be served from the edge and never touch PHP. The basket, the customer account, order history and the list of licence keys are personal and must not be cached anywhere except in their owner’s own browser. The boundary between those two worlds is the most common source of serious defects in online shops: one misconfigured header and the edge starts serving one customer’s basket page to another.

The rule is therefore absolute and not up for optimisation: the presence of a shopping session cookie disqualifies a request from the edge cache, with no exceptions. That is a performance cost for logged-in customers and it is accepted deliberately, because the alternative is leaking order data. Session-dependent fragments, such as the basket counter in the header, are fetched by a separate request after the page loads, which keeps the page shell common to everyone and still cacheable.

Redis shortens what remains inside PHP. In a shop with rich product attributes the heaviest cost comes from metadata queries, because the database joins products against their properties on every filter operation. Those results, along with attribute lists and the category structure, live in the object cache and are invalidated when a product changes rather than when a timer runs out.

#Tax rules that reach into the basket

Any shop selling digital goods across a border runs into a requirement that is not accounting housekeeping but a front-end constraint. An electronic service supplied to a consumer in another EU country is taxed at the buyer’s country rate, and a sale to a business with a valid EU VAT number is settled differently from a sale to a private individual. The shop has to establish the buyer’s status before it can show a final price, validate the VAT number against the registry, and retain evidence of the buyer’s location.

That reaches into the basket and the invoice template, not into a monthly export. It also interacts with caching in a way that catches people out: a price that depends on the visitor’s country cannot be baked into an edge-cached page for everyone. Prices in the catalogue are therefore shown in a defined base form, and the country-dependent final amount is resolved in the basket, where the request is already excluded from the edge cache anyway.

#Security for a product adjacent to finance

A site selling tooling for the financial sector is an attractive target for two reasons at once: it processes payments and it distributes code that customers install on their own sites. The second is the graver one, because a compromised update file propagates automatically to every installation.

That dictates the order of the defences. Payments do not pass through the site; they go to the payment provider, so card data never reaches our server and the shop stores a transaction identifier only. Release files are signed and served only after a licence check, and access to the release panel is separated from ordinary content administration. Security is handled in code and in server configuration rather than by adding another security plugin. Such a plugin runs inside PHP, which is to say after the request has already started the application, it taxes every request and it regularly turns out to be a vulnerability of its own. Filtering at the edge, capability checks on every licence operation and a hardened server configuration cost less and act earlier.

There is a data protection layer too, unavoidable in a shop that issues licence keys. A customer account ties an email address to the list of domains where those licences run, which is information about that company’s infrastructure. It is not sensitive data in the legal sense, but a leak has real consequences for the customer, because it tells an attacker which tools sit on which site. Access to that list is restricted at the API level exactly like order data, and logs deliberately record shortened key identifiers rather than full licence keys.

#Performance, monitoring and maintenance

Work out where the performance budget of a licensing shop actually goes, and the home page turns out not to be the expensive part. The licence endpoint is. Hundreds of customer installations call it on their own schedule, in the middle of the night as readily as at noon, and none of that traffic shows up in visitor statistics. It shows up in server load, and only in server load, which is why it has to be budgeted for before the first marketing campaign rather than after the first outage.

The consequence for monitoring is a separate alarm on that endpoint, independent of the general uptime check. A licence endpoint that stops answering does not cost a conversion the way a slow home page does; it makes hundreds of installations report an update error in the same minute, and support then fields a wave of tickets about a fault that never happened on the customer’s side.

Everything in front of that endpoint is ordinary front-end discipline. Assets are compiled, bundles are split, and code loads only on the pages that use it. Images are processed once at upload instead of on every view, which moves the cost from each request to a single moment the editor never notices. Static files are served through Cloudflare, and with a customer base spread across several continents that is the single largest saving available. None of it helps the licence endpoint, because that request has to reach the application by definition, and the boundary between the two is the design decision worth keeping.

Maintenance covers core, theme and extension updates, log review, backups whose restore path is exercised rather than merely scheduled, and functional changes driven by how the offer develops. A software shop adds one obligation that ordinary retail does not carry: every WordPress update on the shop side has to be reconciled with the compatibility the sold products declare. A shop running the newest release while selling plugins marked compatible with a version from two years ago undermines its own catalogue before any customer has read a word of it.

Testing before a deployment runs against a copy of production, and here the reason is more literal than in most projects. An empty install has no active licences at all, so renewal, expiry and version-check logic has nothing to run against and every test passes by having nothing to do. A real licence set behaves differently: some entries expired last week, some were renewed halfway through a term, a few belong to customers who moved a licence between domains without telling anyone. Only that mixture shows whether the rules match what the terms of sale promise.

#Summary

WordPress can carry software distribution as long as it is treated as the content and commerce layer and not as the whole application. The parts that belong outside it are the ones with hard timing or hard security constraints, which here means two of them: verifying a licence, and handing over a file. Everything else, the catalogue, the versioned documentation, the editorial material and the checkout, sits comfortably where a content management system is strong.

Four decisions carry over to the next project of this kind. Structured product data rather than prose, a separation between the right to use and the right to update, an explicit boundary around what may be cached, and a split between licence verification and file delivery.

What does not carry over is this catalogue’s content model or its licensing rules. They were written for one offer and one set of terms, and a vendor selling perpetual use alongside time-limited support would need a different shape from the first field onwards. The next build therefore starts with a question rather than a template: what exactly does the customer buy, and for how long. The answer settles roughly half the architecture before anyone opens an editor.

Article FAQ

Frequently asked questions

Practical answers to apply the topic in real execution.

SEO-readyGEO-readyAEO-ready4 Q&A
What scope did the pluginfinance.com project cover?#
pluginfinance.com sits in the Logotypes category and was first delivered in 2025. The entities behind it are WordPress, WooCommerce, PHP, JavaScript and React.
How did delivery run for pluginfinance.com?#
The build ran about six weeks and went live in 2025. It sits on WordPress, WooCommerce, PHP, JavaScript and React. The layout came from the client. I built the templates and the content model against it, then checked the paths that carry traffic on a copy of production rather than on an empty install.
What was the hardest technical part of pluginfinance.com?#
Holding WordPress, WooCommerce, PHP, JavaScript and React together took the most care. Content, configuration and code stay in separate layers, so a rollback after launch moves one of them and not all three. Edge cases surface on a production copy, which is why the checks run there.
What part of pluginfinance.com could be reused on another build?#
WordPress, WooCommerce, PHP, JavaScript and React is the part that carries over; that layer looks much the same on the next build. What does not carry over is this project's content model and its integrations, written against one client's data for a Logotypes brief. A second build starts from a scope review, and the quote follows it.

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

Let’s discuss