Title: TNT — Simple Product Add-Ons
Author: Keshab Adhikari
Published: <strong>September 27, 2026</strong>
Last modified: September 27, 2026

---

Search plugins

![](https://ps.w.org/tnt-extras-for-woocommerce/assets/banner-772x250.png?rev=3715161)

![](https://ps.w.org/tnt-extras-for-woocommerce/assets/icon-256x256.png?rev=3715161)

# TNT — Simple Product Add-Ons

 By [Keshab Adhikari](https://profiles.wordpress.org/kesadh/)

[Download](https://downloads.wordpress.org/plugin/tnt-extras-for-woocommerce.1.0.10.zip)

 * [Details](https://wordpress.org/plugins/tnt-extras-for-woocommerce/#description)
 * [Reviews](https://wordpress.org/plugins/tnt-extras-for-woocommerce/#reviews)
 *  [Installation](https://wordpress.org/plugins/tnt-extras-for-woocommerce/#installation)
 * [Development](https://wordpress.org/plugins/tnt-extras-for-woocommerce/#developers)

 [Support](https://wordpress.org/support/plugin/tnt-extras-for-woocommerce/)

## Description

**No bloat, no upsells, no page builder — just optional add-ons that follow your
product through checkout.**

Product Add-Ons lets a store admin attach optional extras to any simple or variable
product — for example an Office Chair at $200 with an Extended Warranty (+$30), 
a Headrest (+$45), a Footrest (+$25) and Premium Assembly (+$50). Shoppers tick 
the add-ons they want on the product page; the total updates instantly with no page
reload, and the selected add-ons and their prices ride along with that product through
the cart, checkout, the resulting order, order emails and any invoice built from
standard WooCommerce order data.

This plugin is intentionally simple: no page builder, no complex conditional logic,
no separate add-on inventory. Just add-ons, priced, optionally imaged, shown in 
one of five ready-made designs.

#### Features

 * Up to 5 add-ons per product, managed from a repeater on the product’s own “Add-
   Ons” tab
 * Drag-and-drop reordering, per-add-on enable/disable, name/description/price/image
   fields
 * Global default position and design, with an optional per-product override
 * Five frontend designs: Classic List, Grid Cards, Compact List, Toggle Switches,
   and Image Cards
 * Live price preview (Product Price / Add-Ons / Total) with zero page reloads
 * Add-on price is only ever added when selected — the product’s own base price 
   is never modified
 * Selections are re-validated and re-priced on the server at Add to Cart — the 
   browser is never trusted for the actual charge
 * Different add-on selections never merge into the same cart line
 * Add-ons appear on the cart and checkout review tables, and are saved to the order
   as line item meta — visible in wp-admin (classic and HPOS), order emails, the
   customer’s account order view, and most invoice/PDF plugins that read standard
   order item meta
 * Works with WooCommerce’s High-Performance Order Storage (HPOS)
 * Graceful when WooCommerce is inactive — the plugin stays dormant instead of causing
   a fatal error
 * Optional data cleanup on uninstall (off by default — your data is safe unless
   you opt in)

#### Known limitations (by design, to keep this simple)

 * The Cart/Checkout **blocks** (as opposed to the classic shortcode-based Cart/
   Checkout pages) are not yet officially declared compatible; the underlying data
   hooks used here are widely supported by WooCommerce Blocks’ backward-compatibility
   layer, but this hasn’t been exhaustively tested against every block-based theme.
 * Add-ons are configured per simple/variable product (variable add-ons apply to
   the whole product, not per-variation).
 * Add-ons don’t carry their own separate stock/inventory tracking.
 * The Product CSV importer/exporter and the REST API do not currently include add-
   on fields.
 * “Order Again” (re-ordering a past order from My Account) re-adds the base product
   but does not currently re-select its add-ons.

## Installation

 1. Upload the plugin folder to `/wp-content/plugins/`, or install the zip via Plugins
    Add New  Upload Plugin.
 2. Activate the plugin. WooCommerce must already be active — if it isn’t, the plugin
    stays installed but inactive and shows a notice until WooCommerce is available.
 3. Go to WooCommerce  Settings  Product Add-Ons to set the default position, design,
    and what’s shown (image/price/description).
 4. Edit a product, open its **Add-Ons** tab, tick “Enable Add-Ons”, and add up to 
    5 add-ons.

## FAQ

### Does this change my product’s actual price?

No. The product’s stored price is never modified. Add-on prices are added only to
the line item shown to the customer, and only for the add-ons they actually select.

### What happens to an order if I later edit or delete an add-on?

Orders already placed keep the name and price that was charged at the time — editing
an add-on afterwards never changes past orders. If you edit an add-on’s price while
it’s still sitting unpurchased in someone’s cart, their cart total will reflect 
the corrected price the next time it recalculates (the same way a normal product
price correction would). If you delete an add-on entirely, any cart that already
had it selected keeps the price it had captured at the time it was added.

### How many add-ons can a product have?

Up to 5. This is a fixed limit in the current version.

### Why don’t I see the Google Pay / Apple Pay / Link button on a product with add-ons?

That’s intentional. Those “express checkout” buttons charge whatever price they’re
shown before the customer ever sees the add-on choices, so letting one through would
silently check out without any add-ons the customer might have wanted. Whenever 
a product has active add-ons, the plugin hides that button so customers go through
the normal Add to Cart flow instead, where the price is always correct. The button
is unaffected on products with no add-ons, and it still appears normally on the 
Cart and Checkout pages (by then the price is already correct).

### Does the add-on price include or exclude tax?

Add-on prices are added directly into the product’s line item, so they automatically
follow that product’s tax class and your store’s normal tax display settings — you
don’t need to configure tax separately for add-ons.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“TNT — Simple Product Add-Ons” is open source software. The following people have
contributed to this plugin.

Contributors

 *   [ Keshab Adhikari ](https://profiles.wordpress.org/kesadh/)

[Translate “TNT — Simple Product Add-Ons” into your language.](https://translate.wordpress.org/projects/wp-plugins/tnt-extras-for-woocommerce)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/tnt-extras-for-woocommerce/),
check out the [SVN repository](https://plugins.svn.wordpress.org/tnt-extras-for-woocommerce/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/tnt-extras-for-woocommerce/)
by [RSS](https://plugins.trac.wordpress.org/log/tnt-extras-for-woocommerce/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.0.10

 * Change: the WordPress.org review team has confirmed and reserved the new slug`
   tnt-extras-for-woocommerce`. Text Domain header and every translation string 
   now updated to match, for real this time — this is the final value going forward.
 * Add: `Requires Plugins: woocommerce` header, flagged as useful by the review 
   team’s automated dependency check since the plugin extends WooCommerce; declares
   the dependency to WordPress core (6.5+) so it can prompt/require WooCommerce 
   to be active before this plugin activates.

#### 1.0.9

 * Fix: reverted the Text Domain header and every translation string from “tnt-extras-
   for-woocommerce” back to “product-add-ons”. WordPress.org’s Plugin Check derives
   its “expected” text domain from the slug currently reserved for this submission,
   which is still `product-add-ons` — the review team has not yet processed the `
   tnt-extras-for-woocommerce` rename requested in 1.0.8, so shipping that value
   now fails every text-domain check. The plugin’s _display_ name stays “TNT Extras
   for WooCommerce” (that satisfies the reviewer’s naming objection); only the internal
   Text Domain reverts, and only until the new slug is confirmed, at which point
   it will be updated to match in a follow-up release.
 * Fix: removed a stray `.DS_Store` file from the plugin folder (“Hidden files are
   not permitted”).

#### 1.0.8

 * Change: renamed the plugin from “Product Add-Ons” to “TNT Extras for WooCommerce”(
   slug: `tnt-extras-for-woocommerce`) at the request of the WordPress.org review
   team — the previous name was judged too close to WooCommerce’s own “Product Add-
   Ons” extension. Text Domain and every translation string updated to match; user-
   facing labels (“Product Add-Ons” settings tab, admin notices) renamed to “TNT
   Extras”.

#### 1.0.7

 * Fix: `WordPress.DB.SlowDBQuery.slow_db_query_meta_key` warnings (4x) on the `
   $wpdb->delete()` cleanup calls in the uninstall routine — added to the existing`
   phpcs:disable`/`phpcs:enable` justification block alongside the direct-query 
   codes already suppressed there.

#### 1.0.6

 * Fix: Text Domain header and every translation string now consistently use “product-
   add-ons”, matching the plugin’s WordPress.org slug (the 1.0.5 changelog entry
   below describing the opposite move was itself a regression — this corrects it
   for good).
 * Fix: all internal class names (previously the generic `AP_` prefix, e.g. `AP_Settings`)
   renamed to a unique, plugin-specific prefix (`Product_Add_Ons_*`) together with
   the plugin’s global helper functions and constants, resolving “non-prefixed” 
   naming warnings from the WordPress.org Plugin Check.
 * Fix: added the missing nonce-verification justification comments on two `$_POST`
   reads in the add-to-cart handler (the add-to-cart form has no dedicated nonce
   in core WooCommerce; selections are always re-validated server-side against the
   product’s own configuration regardless).
 * Fix: `$product` global reassignment in the frontend renderer now carries the 
   same justified `phpcs:ignore` as its declaration (WooCommerce’s own global, not
   one this plugin defines).

#### 1.0.5

 * Fix: resolved a Plugin Check text-domain mismatch — the “Text Domain” header 
   and every translation string now consistently use “addon-products”, matching 
   the plugin’s actual folder/slug (this reverses the 1.0.4 change, which had moved
   the wrong direction).
 * Fix: a translatable string with two “%d” placeholders is now correctly numbered(“%
   1$d”/”%2$d”) so translators can reorder them.
 * Fix: corrected inline `phpcs:ignore` placement for two `$_POST` reads in the 
   cart add-to-cart handling so the documented justification sits on the exact flagged
   line.
 * Fix: added justified `phpcs:ignore` annotations for WooCommerce’s own `$product`
   global in the frontend renderer, and renamed a local `$settings` variable in 
   the uninstall routine to a prefixed name — both were flagged as unprefixed globals.
 * Fix: shortened the plugin’s short description so it’s no longer truncated on 
   WordPress.org.

#### 1.0.4

 * Fix: WordPress.org’s automated Plugin Check failed the submission on three points,
   now all resolved — “Tested up to” bumped to the current WordPress version; the
   Text Domain header (and every translation string in the code) changed from “addon-
   products” to “product-add-ons” to match the plugin’s assigned slug; the “Domain
   Path” header was removed since no bundled translation files are shipped (WordPress.
   org loads translations for hosted plugins automatically, without needing this).
 * Housekeeping: removed the load_plugin_textdomain() call, which is unnecessary
   for WordPress.org-hosted plugins and can trigger a “translation loading was triggered
   too early” notice on WordPress 6.7+; tidied the uninstall routine’s database 
   cleanup to use $wpdb->delete() with clear justification comments instead of raw
   SQL.

#### 1.0.3

 * Fix: plugin upload was rejected with “Your plugin and author URIs are the same”—
   the header had identical Plugin URI and Author URI values. Removed the Author
   URI line (Plugin URI stays topnewthings.com).

#### 1.0.2

 * Fix: Google Pay / Apple Pay / Link “express checkout” buttons on the product 
   page were charging only the base product price, skipping any selected add-ons,
   because those buttons bypass the normal Add to Cart flow entirely. These buttons
   are now hidden on any product page where add-ons are active, so customers are
   guided through the normal flow where the price is always correct; Add to Cart,
   Cart and Checkout are unaffected.

#### 1.0.1

 * Fix: activation could trigger a fatal error (“Class AP_Settings not found”) because
   the activation hook loaded the install class without first loading the settings
   class it depends on. Activation now loads both, in the right order.

#### 1.0.0

 * Initial release: repeater-based per-product add-ons (max 5), 5 frontend designs,
   live price preview, full Cart  Checkout  Order  Invoice persistence, HPOS compatibility.

## Meta

 *  Version **1.0.10**
 *  Last updated **2 days ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 5.8 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [add-ons](https://wordpress.org/plugins/tags/add-ons/)[options](https://wordpress.org/plugins/tags/options/)
   [Product options](https://wordpress.org/plugins/tags/product-options/)[upsell](https://wordpress.org/plugins/tags/upsell/)
   [woocommerce](https://wordpress.org/plugins/tags/woocommerce/)
 *  [Advanced View](https://wordpress.org/plugins/tnt-extras-for-woocommerce/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/tnt-extras-for-woocommerce/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/tnt-extras-for-woocommerce/reviews/)

## Contributors

 *   [ Keshab Adhikari ](https://profiles.wordpress.org/kesadh/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/tnt-extras-for-woocommerce/)