What a Webstepper Plugin Looks Like Before It Ships: Our Review Process
Behind the scenes · Webstepper
What a Webstepper Plugin Looks Like Before It Ships
The engineering standards we apply before any feature reaches your store — written as a plain account of what the code actually shows, not what a marketing page would say.
Trust in a plugin is hard to establish and easy to lose. Store owners install plugins because they have to — WooCommerce’s core doesn’t cover everything, and someone has to fill the gaps. But every plugin you install is code running inside your store, touching your database, handling your customers’ data, and loading on every page request. You’re trusting the author’s judgment in a dozen invisible ways.
This post is a direct account of the standards Webstepper holds to before shipping code. Not claims from a features page, and not a pitch. Just: here’s what we do, here’s where you can verify it.
Both plugins — Smart Cycle Discounts and TrustLens — are available for inspection. Everything described here is verifiable in the code, not inferred from documentation.
Why Code Standards Are a User Problem, Not a Developer Problem
Most WordPress plugin quality discussions happen at a level that’s invisible to the store owner who installs it. You don’t see whether the plugin uses $wpdb->prepare() for database queries or whether it sanitizes form input before storing it. You see whether it works or breaks.
But the invisible layer is where the real risks live. A plugin that skips nonce verification on AJAX handlers is vulnerable to cross-site request forgery — an attacker can trick an admin into triggering actions they didn’t intend. A plugin that outputs unsanitized data opens the door to XSS. A plugin that runs raw SQL queries is one badly-formed input away from a database injection.
These aren’t theoretical concerns. They’re the most common vulnerability classes in WordPress plugins, and they’re consistently exploitable precisely because they’re invisible. When Webstepper ships code, the goal is that none of these windows exist — not because we’ve patched them, but because the code pattern that would create them doesn’t appear in the first place.
WordPress Coding Standards — What They Actually Look Like
WordPress has a formal coding standard for PHP. It covers indentation, naming, spacing, conditionals, and array syntax. Adhering to it isn’t just aesthetic — it keeps the codebase consistent with the surrounding WordPress environment, makes code auditable, and avoids several categories of subtle bugs.
Here’s what that standard looks like in practice in Webstepper’s code:
Yoda conditions. Comparisons are written with the literal on the left: if ( 'percentage' === $discount_type ) rather than if ( $discount_type === 'percentage' ). The reason is defensive — if you accidentally write a single = instead of ==, Yoda conditions produce a parse error rather than silently assigning the value. Small, but it catches a real class of mistakes.
Array syntax. The codebase uses array() throughout, not the short [] syntax. This is the WordPress standard for plugin code submitted to WordPress.org. It’s consistent across every file in both Smart Cycle Discounts and TrustLens.
Tab indentation, not spaces. WordPress uses tabs. Every PHP file in the codebase follows this. It matters less for correctness and more for consistency — a codebase with mixed indentation is harder to review and easier to misconfigure.
Spaces inside parentheses. Function calls are written as function_name( $arg ) rather than function_name($arg). Again, this is the WordPress standard, and it reads clearly when scanning code quickly.
Single quotes by default. String literals use single quotes unless interpolation is needed. This is both a standard and a mild performance preference — no variable interpolation means no parsing overhead, and it avoids a class of accidental escaping errors.
Prefixed class names. Every class in Smart Cycle Discounts is prefixed WSSCD_. Every class in TrustLens uses its own registered prefix. This is a WordPress.org requirement for plugin submission — it prevents naming collisions with other plugins and with WordPress core. Five-character minimum prefix for compliance.
Where to verify this
Open any PHP file in the Smart Cycle Discounts plugin at includes/ — for example, includes/database/repositories/class-campaign-repository.php. Check the indentation (tabs), the array syntax (array()), the spacing inside parentheses, and the class name (WSSCD_Campaign_Repository). This pattern holds consistently across the codebase.
Security Defaults — Nonces, Escaping, Prepared Statements
There are four security patterns that WordPress plugin code must follow consistently. Missing any one of them creates a real vulnerability. In Webstepper’s code, all four are applied by default — not as a special case, but as the baseline pattern every handler follows.
Nonce verification on every AJAX request
When a user interaction triggers a server-side action — saving a campaign, deleting a record, running a bulk operation — WordPress sends an AJAX request. Without nonce verification, an attacker can craft a fake request and execute those same actions on behalf of an authenticated admin.
Smart Cycle Discounts routes every AJAX request through a centralized security class (WSSCD_Ajax_Security) that calls wp_verify_nonce() before any handler runs. Nonces are generated per-request and checked against the expected action. If the check fails, the handler never executes.
Capability checks
Nonce verification confirms that the request came from a legitimate session. Capability checks confirm that the authenticated user actually has permission to perform the requested action. Both are required — a nonce-only check would allow a subscriber-level user to trigger admin-level actions as long as they had a valid session.
The same WSSCD_Ajax_Security class handles capability checks via current_user_can(), enforcing the correct permission level for each action type. The logic handles WordPress’s native capability system as well as plugin-specific custom capabilities like wsscd_manage_campaigns, falling back to manage_woocommerce for users with store management access.
Input sanitization
Every value arriving from a user form or AJAX payload is sanitized before use. For text fields: sanitize_text_field( wp_unslash( $_POST['field'] ) ). For URLs: esc_url_raw(). For integers: absint() or intval(). The sanitization happens at the boundary — before the data enters any downstream logic.
There’s no place in the codebase where raw $_POST or $_GET values are used directly without sanitization. Even values that are only used for display purposes go through sanitize_text_field() — because treating “display-only” as an exception is how XSS vulnerabilities get introduced.
Output escaping
Data stored in the database is sanitized on the way in, but it must also be escaped on the way out — because you don’t always control what ends up stored, and because the correct escape function depends on where the data is being rendered. Webstepper’s code applies context-appropriate escaping throughout:
esc_html()for content inside HTML elementsesc_attr()for HTML attributesesc_url()for href and src valuesesc_js()for inline JavaScript stringswp_kses_post()for rich content that permits a defined subset of HTML
Prepared statements for every database query
Database queries that incorporate user-supplied values are built with $wpdb->prepare(). This separates the SQL structure from the data — the database driver handles proper escaping of values, and SQL injection through malformed input is structurally impossible. The codebase has no raw string-concatenated queries where user input is involved.
Table names, which cannot be parameterized via prepare(), are always derived from $wpdb->prefix (a trusted WordPress-controlled value) and accompanied by a PHPCS ignore comment explaining the rationale — following WordPress.org’s recommended pattern for this specific case.
A Dedicated Security Layer, Not Ad-Hoc Checks
What distinguishes a well-architected codebase from one that just happens to have some security checks is whether security is a layer or a checklist. Checklists fail when a developer forgets to add the check. Layers apply automatically because the code path runs through them regardless.
Smart Cycle Discounts has three dedicated security classes: WSSCD_Security_Manager, WSSCD_Nonce_Manager, and WSSCD_Rate_Limiter. These are not utility functions scattered through handler code — they’re distinct classes with specific responsibilities, wired into the AJAX routing layer so that security checks happen before any handler receives control. The rate limiter exists specifically to protect against brute-force and enumeration attacks on AJAX endpoints.
This architectural choice matters. Adding a nonce check in every handler is error-prone at scale. Centralizing it in the routing layer means forgetting a check in one handler doesn’t create a gap — the gap can’t exist because the architecture doesn’t allow it.
HPOS Compatibility and Why It Matters for Your Store
High-Performance Order Storage (HPOS) is WooCommerce’s modern order storage system. Instead of storing orders in WordPress’s generic post tables, HPOS uses dedicated database tables designed for order data specifically. The result is meaningfully faster order queries, especially on stores with large order volumes.
HPOS was introduced in WooCommerce 7.1 and became the default in WooCommerce 9.x. If you’re running a modern WooCommerce installation, you’re likely using HPOS. And if a plugin you install wasn’t built with HPOS in mind — if it still queries the old wp_posts table for order data — you can see performance regressions and compatibility warnings in your WooCommerce health check.
Both Smart Cycle Discounts and TrustLens are HPOS-compatible. Smart Cycle Discounts is tested up to WooCommerce 9.5 (as of version 2.1.1), and its compatibility with WooCommerce’s custom order tables is declared in the plugin header per WooCommerce’s standard mechanism. TrustLens carries the same declaration at version 1.2.5.
The practical implication: installing either Webstepper plugin will not generate HPOS compatibility warnings in your WooCommerce dashboard, and order lookups will not fall back to the slower legacy tables.
If you’re evaluating discount plugins that might run alongside Smart Cycle Discounts, the post on WooCommerce discount plugins and block checkout compatibility covers a related class of compatibility issues worth understanding before you install something new.
Privacy Posture — What Data Is Collected, What Isn’t
The correct default for a WordPress plugin is to not send your data anywhere. Data collection should be an explicit opt-in, not a baseline behavior.
Smart Cycle Discounts (free version): No customer data is transmitted to external servers. Campaign data, analytics, and configuration stay inside your database. The only external connection the free version makes is to the Freemius licensing SDK on activation — which is standard across thousands of WordPress plugins and is a requirement for the free/Pro licensing split. SSL verification is explicitly enabled in the Freemius configuration (the plugin sets WSSCD_FREEMIUS_SSL_VERIFY to true, unlike plugins that leave it at the Freemius default of disabled).
TrustLens (free version): Customer trust scores, detection signals, and behavioral data are computed locally and stored locally — no data leaves your server. The plugin’s readme states this explicitly, and the code matches: there are no external API calls in the detection or scoring pipeline. The only network communication is the Freemius SDK connection on activation, same as above.
Both plugins ship with full WordPress GDPR privacy integration. They register with WordPress’s built-in privacy export and erasure system, which means customers can request their data through WooCommerce’s standard privacy tools, and their records will be included in exports and removable on request.
TrustLens: HMAC-SHA256 Signing for Sensitive Fingerprints
TrustLens’s linked-account detection identifies customers who might be operating multiple accounts — different email addresses sharing the same shipping address, IP, payment method, phone number, or device fingerprint. This is a genuinely useful fraud-detection signal, but it requires the plugin to store identifiers that could be considered personally identifiable.
Webstepper’s answer to this is pseudonymization. Linked-account fingerprints are not stored as raw values — they’re stored as keyed HMAC-SHA256 hashes. This means the plugin can still detect when two accounts share the same identifier (if the hash matches, the original values matched) without ever storing the raw identifier in a readable form.
The practical implication: if someone gained unauthorized access to the TrustLens database tables, they would see opaque hash values, not customer IP addresses or device fingerprints. The hash is keyed (uses a secret key, not just a fixed algorithm), which means the hashes can’t be reversed or attacked with a precomputed rainbow table without the key.
This is a specific technical choice that costs nothing in terms of detection capability while significantly reducing the privacy risk surface. It’s worth comparing to other linked-account detection approaches that store raw values — the difference is not in what the feature can detect, but in what an attacker would find if they got into the database.
If you want to understand what TrustLens actually does with the signals it gathers, the post on how TrustLens scores a WooCommerce customer covers the full scoring engine in detail.
Compatibility Baseline — PHP, WordPress, WooCommerce
Both plugins carry explicit minimum and tested-up-to version declarations in their headers. As of current releases:
| Requirement | Smart Cycle Discounts 2.1.1 | TrustLens 1.2.5 |
|---|---|---|
| PHP minimum | 7.4 | 7.4 |
| WordPress minimum | 6.4 | 6.4 |
| WordPress tested up to | 7.0 | 7.0 |
| WooCommerce minimum | 8.0 | 8.0 |
| WooCommerce tested up to | 9.5 | 9.5 |
| HPOS compatible | ✓ | ✓ |
| Block cart/checkout support | ✓ | ✓ |
PHP 7.4 as the minimum reflects a real trade-off. PHP 7.4 is end-of-life, which means a plugin targeting it accepts some older hosting environments in exchange for a wider install base. PHP 8.x is more performant and has stricter typing. Both plugins run cleanly on PHP 8.x — the 7.4 minimum is a floor, not a target.
WordPress 6.4 as the minimum aligns with the version that shipped the updated block editor APIs that both plugins use for their admin interfaces. Going lower would require compatibility shims for functionality that WooCommerce itself requires to be modern.
What Doesn’t Ship
A codebase that hasn’t accumulated dead code, experimental features in half-built states, and forgotten debug utilities is harder to maintain than one that has. The instinct to “just leave it in, it doesn’t hurt anything” is how plugins end up with security surface area they don’t know about and performance overhead they can’t account for.
Smart Cycle Discounts’s autoloader maintains an explicit class map — every class the plugin uses is registered by name and file path. There is no dynamic class discovery scanning directory trees. This means there’s no mystery about what the plugin loads; the map is the complete inventory.
When Webstepper removes a feature or refactors an architecture, the old code goes with it. The recent removal of the guardrails system (the pre-launch “Continue anyway?” modal) and the badge_surfaces dead code are recent examples. These were not deprecated with a compatibility wrapper — they were deleted. The plugin’s footprint doesn’t grow with historical artifacts.
The Pro tier features are declared explicitly in the plugin header via the Freemius @fs_premium_only annotation. There’s a clear, verifiable line between what ships in the free version and what requires a Pro license — not inferred from behavior, but declared in the file. You can open smart-cycle-discounts.php and read the list directly.
How to read the free/Pro split for yourself
In Smart Cycle Discounts’s main plugin file (smart-cycle-discounts.php), the @fs_premium_only comment lists every file that is excluded from the free version. If a class or feature isn’t on that list and doesn’t appear in a Pro-only file path, it’s in the free version. No inference required.
The Honest Version
Writing a post like this creates an obvious incentive to present everything in the best light. So here’s the honest version of a few things.
These are the standards the codebase currently meets. Code is never finished. There are areas where coverage could be deeper, where documentation could be clearer, and where future development will need to hold the same standard. There’s no automated continuous integration pipeline that enforces these patterns on every commit; the discipline is in the process and the review, not a fully automated gate. That’s a gap worth naming.
The free version includes Campaign Intelligence in Smart Cycle Discounts and all eight detection modules in TrustLens. These are genuinely useful features, not crippled trials. But the free/Pro split exists because the business needs to sustain development, and some features — the full analytics dashboard in Smart Cycle Discounts, the automation rules in TrustLens, the advanced subscription controls — are Pro. That split is what allows the free version to be as capable as it is.
If you want to evaluate either plugin before committing, the free version of Smart Cycle Discounts on WordPress.org is the full plugin, not a sample. Install it, run it, and see whether the behavior matches what’s described here. That’s a better test than any post can offer.
The codebase for both plugins is the real record of what Webstepper ships. This post is a guide to reading it.
Key Points
- WordPress coding standards — Yoda conditions,
array()syntax, tab indentation, prefixed class names — are applied consistently across both Webstepper plugins, not just where convenient. - Security defaults are architectural, not optional. Every AJAX request goes through centralized nonce verification and capability checks before any handler runs. Input is sanitized at the boundary. Output is escaped in context.
- Both Smart Cycle Discounts and TrustLens are HPOS-compatible and tested up to WooCommerce 9.5, so modern WooCommerce stores will not see compatibility warnings.
- In the free version of both plugins, no customer data is transmitted to external servers. All scoring, analytics, and campaign data stay inside your database. GDPR privacy export and erasure are supported through WordPress’s native privacy tools.
- TrustLens stores linked-account fingerprints as keyed HMAC-SHA256 hashes — not raw identifiers — reducing the privacy risk if the database is ever accessed without authorization.
- The free/Pro split is declared explicitly in each plugin file header. There is no ambiguity about what is included at which tier.