EnterpriseUpdated 9 min read
WordPress VIP development: code review, caching and releases
Write PHP that passes WordPress VIP coding standards and code review: PHPCS rulesets, cached helpers, bounded queries, page caching, cron and releases.
By Hamza Ahmad AslamAI & WordPress Developer | Speed Optimization & Site Security

On this page
- What WordPress VIP development changes in your code
- How to run the WordPress VIP coding standards locally
- What the VIP code analysis bot checks
- Which review failures should you fix first
- Replace uncached core functions where VIP provides a cached helper
- Remove unbounded queries
- Prefer WordPress query APIs over direct SQL
- Give remote requests a failure strategy
- Do not write persistent application state into the code filesystem
- Avoid queries that depend on an unindexed postmeta value
- How VIP caching changes personalized output
- How scheduled and long-running work should run
- How the VIP deployment workflow works
- Run the application in VIP's local environment
- How to verify a release instead of assuming it worked
- What to do next
- Frequently asked questions
Short answer: WordPress VIP development requires code that fits a managed platform with automated pull request analysis, persistent caching, restricted filesystem access, and branch-based deployments. Write bounded queries, keep front-end responses cacheable, move expensive work away from requests, and verify each release through logs, cache headers, and performance data.
At Gallery Media Group in New York, I resolved production tickets and developed features on WordPress VIP, working with other teams to define requirements, review code and deploy performance improvements.
This guide covers the coding standards, review failures, caching patterns, query design, scheduled work, deployment workflow, and release checks involved in WordPress VIP development.
What WordPress VIP development changes in your code
WordPress VIP is not a conventional WordPress server where application developers control Apache, NGINX, PHP configuration, plugins through wp-admin, and arbitrary writable directories.
The WordPress on VIP platform documentation (opens in a new tab) confirms several constraints that affect application design.
VIP runs NGINX, so .htaccess files are not available. Platform-wide NGINX directives cannot be customized per site. Plugins and themes are deployed through source control rather than installed or edited through wp-admin.
The application filesystem should also be treated differently from a traditional server. Application code is deployed from Git and is not a place for runtime-generated persistent files.
/wp-content/uploads/ maps to the VIP File System, an external object store. Temporary local work belongs in the writable system temporary directory, normally reached through get_temp_dir().
VIP supplies several caching layers:
- Page caching can serve complete responses from edge servers without running PHP.
- The WordPress object cache uses persistent Memcached storage for application data.
- The Query Cache provides lightweight, transparent in-memory caching for many database queries, including post lookups.
- Static assets and media are delivered through VIP's edge infrastructure.
Those layers make cache behavior part of application architecture, not a final optimization pass.
How to run the WordPress VIP coding standards locally
Install the current WordPress VIP coding standards before opening a pull request.
The official Automattic VIP Coding Standards repository (opens in a new tab) documents the Composer installation:
composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev automattic/vipwpcs
For current VIP Go applications, run the WordPress-VIP-Go ruleset:
./vendor/bin/phpcs --standard=WordPress-VIP-Go .
WordPressVIPMinimum still exists, but the project documents it for the older WordPress.com VIP platform. WordPress-VIP-Go is the appropriate ruleset for current VIP Go application code.
The phrase PHPCS WordPress-VIP-Go is useful shorthand, but the package also depends on rules from WordPress Coding Standards and related PHPCS standards.
A PHPCS failure identifies the file, line, severity, message, and sniff code. Treat that sniff code as the starting point for investigation rather than hiding the result with an ignore annotation.
What the VIP code analysis bot checks
The VIP Code Analysis Bot (opens in a new tab) analyzes pull requests made to branches in an application's wpcomvip repository.
Its checks include PHPCS analysis, PHP linting, SVG analysis, and vulnerability or update scanning. PHPCS analysis uses WordPress-VIP-Go and PHPCompatibilityWP for altered code.
A VIP code review warning is not the same as a manual rejection from a VIP engineer. VIP recommends required GitHub status checks so detected issues are addressed before merging.
That distinction matters for release design. Automated analysis provides feedback on the pull request, while your repository's branch protections determine what contributors can merge.
Which review failures should you fix first
Replace uncached core functions where VIP provides a cached helper
Some WordPress functions intentionally perform database work on every call. VIP provides cached alternatives for several of them.
Before:
$attachment_id = attachment_url_to_postid( $url );
After:
$attachment_id = wpcom_vip_attachment_url_to_postid( $url );
VIP also documents cached helpers for operations such as adjacent-post lookups, user post counts, URL-to-post-ID resolution, and oEmbed retrieval.
These replacements matter most on code paths reached repeatedly by front-end requests.
Remove unbounded queries
A query using posts_per_page => -1 removes the normal result limit. That becomes increasingly expensive as the matching dataset grows.
Before:
$query = new WP_Query(
array(
'post_type' => 'article',
'post_status' => 'publish',
'posts_per_page' => -1,
)
);
Use an application-enforced page size instead. If you only need IDs and do not need pagination totals, request exactly that:
$query = new WP_Query(
array(
'post_type' => 'article',
'post_status' => 'publish',
'posts_per_page' => $page_size,
'no_found_rows' => true,
'fields' => 'ids',
)
);
$article_ids = $query->posts;
no_found_rows => true tells WP_Query not to calculate total matching rows when those totals are unnecessary. fields => 'ids' returns post IDs instead of complete post objects.
Do not copy those arguments mechanically. If the interface needs pagination totals or full post objects, request only the required data.
Prefer WordPress query APIs over direct SQL
Direct database access is sometimes necessary, but VIP recommends WordPress APIs whenever they can express the query.
Avoid application code shaped like this:
global $wpdb;
$ids = $wpdb->get_col(
"SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish'"
);
Use WP_Query when querying posts:
$query = new WP_Query(
array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $page_size,
'no_found_rows' => true,
'fields' => 'ids',
)
);
$ids = $query->posts;
If direct SQL cannot be avoided, keep it bounded, inspect it with EXPLAIN, prepare dynamic values, and cache expensive results where appropriate.
Give remote requests a failure strategy
A remote service must not control front-end response time indefinitely. VIP's remote data guidance (opens in a new tab) recommends the WordPress HTTP API and caching.
Before:
$response = wp_remote_get( $url );
For front-end data that does not require an immediate fresh response, VIP provides a cached helper:
$body = wpcom_vip_file_get_contents( $url );
That helper has a documented default timeout of three seconds and can return previously cached data when a fresh request fails.
If an uncached HTTP request is required, use the WordPress HTTP API with a reviewed timeout and error path. Do not put an uncached dependency on every page request.
Do not write persistent application state into the code filesystem
This pattern assumes a writable application directory:
file_put_contents(
WP_CONTENT_DIR . '/generated/report.json',
$json
);
If the file is temporary processing state, target WordPress's temporary directory:
$temp_file = get_temp_dir() . 'report.json';
file_put_contents( $temp_file, $json );
Filesystem operations can still receive PHPCS review warnings because their safety depends on the destination.
For persistent media, use the uploads path and WordPress media APIs. Do not use local files as a replacement for a database, object cache, queue, or external object storage.
Avoid queries that depend on an unindexed postmeta value
On VIP, postmeta has an index on meta_key and a platform index combining meta_key with meta_value. A query against meta_value without a matching key cannot benefit from that combined index.
A design like this should trigger a schema discussion:
$query = new WP_Query(
array(
'post_type' => 'article',
'meta_query' => array(
array(
'value' => 'premium',
'compare' => '=',
),
),
)
);
For categorical data that participates heavily in filtering, a taxonomy is often a better model:
$query = new WP_Query(
array(
'post_type' => 'article',
'posts_per_page' => $page_size,
'no_found_rows' => true,
'tax_query' => array(
array(
'taxonomy' => 'access_level',
'field' => 'slug',
'terms' => array( 'premium' ),
),
),
)
);
For expensive search, taxonomy, or metadata-driven discovery across large datasets, evaluate VIP Enterprise Search. Test individual queries rather than sending every WP_Query to Elasticsearch.
Avoid large post__not_in lists as well. They create query variants that are harder to cache efficiently. Where practical, fetch a bounded candidate set and exclude a small number of IDs in PHP.
How VIP caching changes personalized output
VIP caching works best when many visitors can receive the same page response.
Server-side user-specific HTML reduces that advantage. Logged-in WordPress requests bypass the page cache, and several session or authentication cookies also cause a cache bypass.
For anonymous pages, keep the main HTML shared whenever possible. Load small user-specific components through client-side requests to fast endpoints.
Examples include saved-state buttons, account indicators, recommendation widgets, or entitlement checks. The shared document remains page-cacheable while the personalized fragment is fetched separately.
For a limited number of audience variants, VIP also provides a Cache Personalization API. Use segmentation only where it has a defined content requirement because each extra cache variant reduces cache reuse.
Do not start PHP sessions globally for convenience. Session-bearing requests bypass the page cache and send more traffic to origin PHP.
How scheduled and long-running work should run
VIP uses WordPress Cron together with Automattic's Cron Control infrastructure. Core /wp-cron.php execution is disabled on the platform, and Cron Control manages due events independently of incoming page views.
Use scheduled work for imports, syndication, maintenance, deferred processing, and other tasks that should not hold open a visitor request.
Long jobs should be resumable. Process a bounded unit, record progress, then schedule or continue another unit. That structure reduces the cost of retries and avoids making one worker responsible for the entire workload.
You can inspect scheduled events through WP-CLI on an environment:
vip @example-app.production -- wp cron event list
Batch logs are useful when scheduled jobs fail because cron and WP-CLI activity runs separately from normal web requests.
How the VIP deployment workflow works
Every VIP application receives a repository in the wpcomvip GitHub organization. WordPress repositories start from VIP's skeleton structure, with directories for custom MU plugins, plugins, themes, private files, language files, and vip-config.
Each VIP environment can track a repository branch. Under VIP Default Deployment (opens in a new tab), a commit reaching the configured branch triggers a deployment to that environment.
A normal release flow is:
- Create a feature branch and test the change locally.
- Run PHPCS and project tests before opening the pull request.
- Review VIP Code Analysis Bot findings on the pull request.
- Merge into the branch assigned to a non-production environment.
- Exercise the change there with realistic data and cache conditions.
- Merge the approved change into the branch assigned to production.
- Watch the deployment and verify the application after it completes.
A WordPress VIP development workflow should therefore treat the pull request, branch mapping, and deployment environment as separate controls.
Run the application in VIP's local environment
VIP-CLI currently exposes local environments through vip dev-env.
From a cloned application repository:
vip dev-env create --slug=vip-local --app-code="$PWD"
vip dev-env start --slug=vip-local
vip dev-env exec --slug=vip-local -- wp post list
vip dev-env info --slug=vip-local reports the local environment state. STATUS UP means the containers are running, while NGINX URLS identifies the local site addresses.
Local environments include VIP-specific services such as the persistent object cache. They are useful for reproducing platform behavior, but production data volume and traffic still require testing in an appropriate VIP environment.
How to verify a release instead of assuming it worked
Start with deployment status in the VIP Dashboard. Default Deployment exposes build, preparation, and deployment logs for the commit being released.
Then inspect application Runtime Logs:
vip @example-app.production logs
Look for new PHP fatals, warnings, notices, repeated HTTP failures, or batch errors that align with the deployment.
Check Slow Query Logs when the change affects content retrieval. Compare new queries with the intended limits and indexes. Query Monitor is also useful on permitted environments for inspecting HTTP calls, object-cache operations, and database queries.
Verify edge behavior from a terminal:
curl -Is "https://your-site.example/" | grep -i '^x-cache:'
Example output:
x-cache: HIT
HIT means the response came from the page cache. MISS means the requested response was not already cached, while BYPASS means the request was intentionally handled by origin.
Unexpected repeated bypasses deserve investigation. Check cookies, sessions, authentication behavior, and cache-control headers before blaming PHP performance.
After the release, review page-cache hit rate, object-cache behavior, origin responses, slow queries, and PHP activity in VIP's monitoring tools. A successful deployment only proves that code reached the environment. It does not prove the new code performs correctly.
What to do next
If the platform move is still being planned, work through the WordPress VIP migration checklist before changing application architecture. Use the high-traffic WordPress architecture article when reviewing cache boundaries, database access, and asynchronous work.
After deploying, use the TTFB diagnostic guide to separate edge, PHP, database, and remote-service delays. For implementation, review the WordPress VIP development service when you need code review, migration work, performance analysis, or release support.
Frequently asked questions
What is the difference between WordPress-VIP-Go and WordPressVIPMinimum?
WordPress-VIP-Go is the VIP Coding Standards ruleset for current VIP Go applications. WordPressVIPMinimum remains in the package for the older WordPress.com VIP platform, so new VIP Go projects should run WordPress-VIP-Go.
Does every WordPress VIP pull request require manual approval from VIP?
No. Pull requests in a wpcomvip repository receive automated analysis from the VIP Code Analysis Bot. Repository status-check and review rules determine what can be merged, while some changes may still require discussion with VIP depending on the application or platform concern.
Can WordPress VIP code use the local filesystem?
Runtime code should not assume that application directories are writable. Temporary operations can use the system temporary directory, while /wp-content/uploads/ maps to the VIP File System and should be handled through WordPress-compatible media workflows.
How do you know whether a WordPress VIP release improved performance?
Compare the affected requests before and after deployment using VIP Runtime Logs, Slow Query Logs, cache metrics, Query Monitor, and application monitoring. Also inspect x-cache response headers so an origin performance change is not confused with a change in page-cache behavior.
How this article was made: drafted with AI assistance from a researched brief, then checked against primary documentation before publishing.
Share this article
Enjoyed this? Get the next article by email.
Keep reading
Enterprise7 min read
Migrating to WordPress VIP: a technical checklist
A WordPress VIP migration is a staged move of code, database content, media, configuration, and launch operations onto VIP's deployment and runtime model.
- WordPress VIP
- Enterprise
- Migration
Enterprise7 min read
High-traffic WordPress architecture: the layers that carry the load
For high traffic WordPress, the edge and full-page cache should absorb most anonymous page views before PHP runs. Capacity problems appear when too much traffic reaches PHP, the object cache, the database, search, or media processing at once.
- WordPress
- Architecture
- Performance
Enterprise7 min read
WordPress CI/CD with GitHub Actions: tests, builds and safe deploys
A WordPress CI/CD pipeline in GitHub Actions should test every pull request, build one repeatable release artifact, and deploy only code after approval. Keep uploads, secrets, and the database outside the repository, then switch releases with a symlink so rollback does not require copying files over the live site.
- WordPress
- Enterprise
- Automation