{"id":364189,"date":"2026-09-13T17:40:48","date_gmt":"2026-09-13T17:40:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/profit-forge-for-woocommerce\/"},"modified":"2026-09-13T17:40:40","modified_gmt":"2026-09-13T17:40:40","slug":"profitforge","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/profitforge\/","author":23513346,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.1","requires":"6.5","requires_php":"8.2","requires_plugins":null,"header_name":"Profit Forge for WooCommerce","header_author":"Avakode","header_description":"Monthly money audit for your store: coupon stacking, refunds without restock and duplicate paid orders \u2014 with order-level evidence, the amount in dollars and the steps to fix it. Your order data never leaves the store.","assets_banners_color":"1f1813","last_updated":"2026-09-13 17:40:40","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/profit-forge.com","header_author_uri":"https:\/\/avakode.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":45,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.0":{"tag":"1.1.0","author":"avakodeforge","date":"2026-09-13 17:40:40","revision":3694017}},"upgrade_notice":{"1.1.0":"<p>The scan now tells you what it will and will not check before it runs. Nothing to do on upgrade.<\/p>","1.0.2":"<p>The scan window cap is gone and every report line is shown to everyone. Nothing in the plugin waits on a key.<\/p>","1.0.0":"<p>First public release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3694016,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3694016,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3694016,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3694016,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3694016,"resolution":"1","location":"assets","locale":"","width":1280,"height":1000},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3694016,"resolution":"2","location":"assets","locale":"","width":1120,"height":440},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3694016,"resolution":"3","location":"assets","locale":"","width":1120,"height":440},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3694016,"resolution":"4","location":"assets","locale":"","width":1280,"height":1000}},"screenshots":{"1":"The report: what the scan will check on this store, the total it found, and the window it covers.","2":"A finding with its evidence lines, the order numbers behind it, and the steps that stop it recurring.","3":"Duplicate paid orders \u2014 the same cart paid for twice, both order numbers, and what to do before the bank turns it into a chargeback.","4":"Settings: the scan window, how many orders per batch, the alert threshold, and which rules run."}},"plugin_section":[],"plugin_tags":[8533,591,265792,37994,286],"plugin_category":[45],"plugin_contributors":[273812],"plugin_business_model":[],"class_list":["post-364189","plugin","type-plugin","status-publish","hentry","plugin_tags-audit","plugin_tags-coupons","plugin_tags-reconciliation","plugin_tags-refunds","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-avakodeforge","plugin_committers-avakodeforge"],"banners":{"banner":"https:\/\/ps.w.org\/profitforge\/assets\/banner-772x250.png?rev=3694016","banner_2x":"https:\/\/ps.w.org\/profitforge\/assets\/banner-1544x500.png?rev=3694016","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/profitforge\/assets\/icon-128x128.png?rev=3694016","icon_2x":"https:\/\/ps.w.org\/profitforge\/assets\/icon-256x256.png?rev=3694016","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/profitforge\/assets\/screenshot-1.png?rev=3694016","caption":"The report: what the scan will check on this store, the total it found, and the window it covers."},{"src":"https:\/\/ps.w.org\/profitforge\/assets\/screenshot-2.png?rev=3694016","caption":"A finding with its evidence lines, the order numbers behind it, and the steps that stop it recurring."},{"src":"https:\/\/ps.w.org\/profitforge\/assets\/screenshot-3.png?rev=3694016","caption":"Duplicate paid orders \u2014 the same cart paid for twice, both order numbers, and what to do before the bank turns it into a chargeback."},{"src":"https:\/\/ps.w.org\/profitforge\/assets\/screenshot-4.png?rev=3694016","caption":"Settings: the scan window, how many orders per batch, the alert threshold, and which rules run."}],"raw_content":"<!--section=description-->\n<p>Your store leaks money in cents. A coupon that stacked when it should not have. A refund where the goods never came back to stock. A customer charged twice because the checkout button was clicked twice. Each one is small. A month of them is not.<\/p>\n\n<p><strong>Profit Forge<\/strong> scans your orders and reports what it found \u2014 with the order numbers, the amount in dollars and the steps that stop it happening again.<\/p>\n\n<h4>What it reports<\/h4>\n\n<ul>\n<li><strong>Coupon stacking<\/strong> \u2014 an \"individual use only\" coupon that ended up combined with other coupons, and how much extra discount that gave away.<\/li>\n<li><strong>Refund without restock<\/strong> \u2014 money refunded, goods never returned to stock, and the inventory value now missing.<\/li>\n<li><strong>Duplicate paid orders<\/strong> \u2014 the same cart and email paid for twice within minutes, before the customer's bank turns it into a chargeback.<\/li>\n<\/ul>\n\n<p>Every finding carries the order numbers behind it. Nothing is reported that cannot be shown on an order screen.<\/p>\n\n<h4>Your data stays in your store<\/h4>\n\n<p>The scan runs inside WordPress. This plugin makes <strong>no external requests at all<\/strong> \u2014 no analytics, no phoning home, no order data sent anywhere. Nothing leaves your server. The one place a request can happen is the separate Pro add-on reading your own gateway statement, and only if you give it a key \u2014 see External services below.<\/p>\n\n<h4>How it works<\/h4>\n\n<ol>\n<li>Activate. No account, no key, no setup wizard.<\/li>\n<li>Run a scan \u2014 it processes orders in the background in batches, so a busy store keeps serving customers.<\/li>\n<li>Read the report: total found, findings grouped by rule, evidence per finding, fix steps.<\/li>\n<\/ol>\n\n<p>You choose the window: a rolling number of days, the last full calendar month, or all the order history you have. Nothing about the scan is capped, metered or time-limited.<\/p>\n\n<h4>A note on precision<\/h4>\n\n<p>A false accusation costs more than a missed leak. Every rule stays silent when it cannot prove its case: a coupon whose settings were deleted, a refund on a product that does not track stock, two orders from the same cart a week apart. If the report says nothing, that means nothing was proven \u2014 not that the rule did not run. Rules that could not run are listed with the reason.<\/p>\n\n<h4>Pro<\/h4>\n\n<p>A separate add-on adds nine more rules (gateway fees against your rate card, shipping charged below label cost, single-use coupon reuse, coupon on top of a sale price, partial refund above the line total, tax class with no matching rate, negative margin after cost of goods, paid orders stuck on hold), a printable report, CSV export and a monthly email.<\/p>\n\n<p>Those rules and screens live in the other plugin \u2014 they are not in this one, switched off. Everything this plugin ships is on, for everyone, with no key: every rule it has, the whole scan window, and every line of every report.<\/p>\n\n<h3>Hooks<\/h3>\n\n<h4>profitforge\/leak_found<\/h4>\n\n<p>Fires once per scan, right after the report is saved, when the new findings\nfound by that scan add up to at least the alert threshold (Settings \u2192\n\"Alert threshold\", $50 by default). One e-mail to the site admin also goes\nout through <code>wp_mail()<\/code> at the same time \u2014 this hook fires either way, so an\nintegration does not depend on outbound mail being configured on the site.<\/p>\n\n<pre><code>do_action( 'profitforge\/leak_found', $report_id, $total_cents, $count, $top_rule )\n<\/code><\/pre>\n\n<ul>\n<li><code>$report_id<\/code> (int) \u2014 the id of the scan run whose report contains these findings.<\/li>\n<li><code>$total_cents<\/code> (int) \u2014 the sum of the new findings that crossed the threshold, in cents. Findings marked \"observe\" and findings already marked \"Fix confirmed\" at an equal or higher amount are not counted here.<\/li>\n<li><code>$count<\/code> (int) \u2014 how many findings that sum is made of.<\/li>\n<li><code>$top_rule<\/code> (string) \u2014 the id of the rule that contributed the largest amount (for example <code>R04<\/code>).<\/li>\n<\/ul>\n\n<p>This is how FlowForge (or any other plugin) can route a Profit Forge leak\ninto its own automation without parsing the e-mail. Free rules count the same\nas Pro rules here \u2014 the hook does not check which add-on found the money.<\/p>\n\n<h3>External services<\/h3>\n\n<p><strong>This plugin connects to nothing.<\/strong> It has no analytics, no update server of its own, no licence check and no telemetry. Everything below is about the separate Pro add-on, and is listed here so the answer is in one place.<\/p>\n\n<h4>Stripe (Pro add-on only, and only if you add a key)<\/h4>\n\n<p>The Pro add-on can check the fee Stripe kept against your rate card. To do that it reads your own Stripe statement.<\/p>\n\n<ul>\n<li><strong>What it is:<\/strong> the Stripe API, <code>https:\/\/api.stripe.com\/v1\/balance_transactions<\/code>.<\/li>\n<li><strong>When it happens:<\/strong> only after you paste a restricted, read-only Stripe key on the Pro settings screen, and then only while a scan is running or when you press \"Test connection\". No key, no requests \u2014 the rules fall back to what the Stripe payment plugin already stored on each order.<\/li>\n<li><strong>What is sent:<\/strong> your key, the date range being scanned and a page cursor. <strong>No order, customer or product data is sent<\/strong> \u2014 matching a transaction to an order happens on your own server, after the answer comes back.<\/li>\n<li><strong>What comes back:<\/strong> your own charges and refunds \u2014 amount, fee, currency, card country and brand.<\/li>\n<li><strong>Your key:<\/strong> stored encrypted (libsodium) with a secret you put in <code>wp-config.php<\/code>; without that secret the add-on refuses to store the key at all. Only the last four characters are ever shown.<\/li>\n<li>Stripe's terms: https:\/\/stripe.com\/legal\/ssa \u2014 Stripe's privacy policy: https:\/\/stripe.com\/privacy<\/li>\n<\/ul>\n\n<p>PayPal fees are not read over the network at all; they come from the fee the PayPal plugin records on the order, or from a statement you export yourself.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate WooCommerce first.<\/li>\n<li>Install this plugin from Plugins \u2192 Add New, or upload the folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate.<\/li>\n<li>Go to <strong>WooCommerce \u2192 Profit Forge<\/strong> and press <strong>Run scan<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20any%20of%20my%20order%20data%20leave%20the%20site%3F\"><h3>Does any of my order data leave the site?<\/h3><\/dt>\n<dd><p>No. The free plugin makes no outbound HTTP requests. The rules run on your server against your own database.<\/p>\n\n<p>The Pro add-on can make one kind of request, and only if you ask it to: with a read-only Stripe key it reads your own Stripe statement to check the fees. Even then no order data is sent \u2014 it asks Stripe for your transactions and matches them to orders here. See External services above.<\/p><\/dd>\n<dt id=\"will%20the%20scan%20slow%20down%20my%20store%3F\"><h3>Will the scan slow down my store?<\/h3><\/dt>\n<dd><p>The scan runs in the background through Action Scheduler in batches of 500 orders. Nothing happens on the front end, and you can leave the page while it runs.<\/p><\/dd>\n<dt id=\"why%20does%20the%20report%20say%20a%20rule%20was%20skipped%3F\"><h3>Why does the report say a rule was skipped?<\/h3><\/dt>\n<dd><p>Because the data it needs is not there \u2014 for example the tax rate table when tax is disabled. A skipped rule is listed with the reason, so silence is never mistaken for \"all clear\".<\/p><\/dd>\n<dt id=\"it%20found%20a%20duplicate%20order%20that%20was%20not%20a%20duplicate.%20what%20now%3F\"><h3>It found a duplicate order that was not a duplicate. What now?<\/h3><\/dt>\n<dd><p>Tell us \u2014 that is a bug, not a matter of taste. Rules are held to zero false findings on a clean test store, and a rule that cannot prove its case is supposed to stay quiet.<\/p><\/dd>\n<dt id=\"does%20it%20change%20anything%20in%20my%20store%3F\"><h3>Does it change anything in my store?<\/h3><\/dt>\n<dd><p>No. The plugin reads orders and writes its own findings table. It never edits an order, a refund, a coupon or a product.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Before a scan runs, the screen now states what it will and will not check on this store, and why \u2014 with a real example line instead of a promise. A rule that cannot run names the data it is missing.<\/li>\n<li>The scan preview and the contract card now agree on how many orders are in the window; the two could previously quote different figures for the same scan.<\/li>\n<li>A case reopened by a later scan keeps its \"fix applied\" date, and a re-test can no longer quietly demote a finding you already confirmed.<\/li>\n<li>Findings and their re-test outcomes are now published in a shared format, so a dashboard plugin installed alongside can read this plugin's results without scraping the screen. Nothing leaves your server: this plugin still makes no external requests.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>The scan window is no longer capped. Any store can scan a rolling number of days, the last full calendar month, or its entire order history \u2014 the \"All available order history\" option is now always on the Settings screen.<\/li>\n<li>Findings that share one cause are grouped into a single case for everyone.<\/li>\n<li>The re-test outcome (\"not repeated on N later orders\" \/ \"repeated on order X\") is now shown to everyone. It was always being calculated; now it is always displayed.<\/li>\n<li>Nothing in this plugin is switched off pending a key, a trial or a quota.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Text domain now matches the plugin slug, so translations load from translate.wordpress.org.<\/li>\n<li>readme: the Contributors field names the plugin owner's WordPress.org account.<\/li>\n<li>Fix: switching a rule off on the Settings screen now actually switches it off (rule ids kept their case in one place and lost it in another).<\/li>\n<li>Honest states: a run that skipped a rule no longer reports \"every rule ran\"; a finding that left the report window is no longer shown as resolved; a month with nothing found is told apart from a month in which the scheduled scan never ran; a report that cannot be fetched says so instead of staying silent.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First public release: coupon stacking, refund without restock and duplicate paid orders, each with the order numbers behind it, the amount and the steps that stop it recurring.<\/li>\n<\/ul>","raw_excerpt":"Finds money lost to coupon stacking, refunds without restock and duplicate paid orders \u2014 evidence, dollars, fix steps.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/364189","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=364189"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/avakodeforge"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=364189"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=364189"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=364189"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=364189"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=364189"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=364189"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}