{"id":355757,"date":"2026-08-21T07:16:47","date_gmt":"2026-08-21T07:16:47","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/cost-margin-pricing-for-woocommerce\/"},"modified":"2026-08-21T07:16:19","modified_gmt":"2026-08-21T07:16:19","slug":"pihlfelt-cost-margin-pricing-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/pihlfelt-cost-margin-pricing-for-woocommerce\/","author":21133816,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1","requires":"6.5","requires_php":"8.1","requires_plugins":null,"header_name":"Pihlfelt Cost & Margin Pricing for WooCommerce","header_author":"Pihlfelt","header_description":"Calculate sale prices from purchase prices with margin rules, supplier price lists, multi-currency costs and price rounding. Writes to WooCommerce core COGS.","assets_banners_color":"106f68","last_updated":"2026-08-21 07:16:19","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/pihlfelt.se\/plugins\/pihlfelt-cost-margin-pricing-for-woocommerce","header_author_uri":"https:\/\/pihlfelt.se","rating":0,"author_block_rating":0,"active_installs":0,"downloads":29,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"pihlfelt","date":"2026-08-21 07:16:19"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3658407,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3658407,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3658407,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3658407,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3658407,"resolution":"1","location":"assets","locale":"","width":1611,"height":1181},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3658407,"resolution":"2","location":"assets","locale":"","width":1625,"height":903},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3658407,"resolution":"3","location":"assets","locale":"","width":1634,"height":765},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3658407,"resolution":"4","location":"assets","locale":"","width":1856,"height":824},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3658407,"resolution":"5","location":"assets","locale":"","width":1856,"height":602},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3658407,"resolution":"6","location":"assets","locale":"","width":1626,"height":1020},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3658407,"resolution":"7","location":"assets","locale":"","width":1420,"height":691},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3658407,"resolution":"8","location":"assets","locale":"","width":1372,"height":786}},"screenshots":{"1":"Price runs \u2014 preview every change before applying: old and new price, the resulting real margin, and exactly which parameters built each price. Large changes need a per-row tick; every applied run has one-click Undo.","2":"Import, step 2 \u2014 the supplier's file with auto-detected separator and encoding; map the columns once and the mapping is remembered per supplier.","3":"Import, step 3 \u2014 every row matched to your products with cost changes, calculated prices and the full calculation breakdown; large changes wait for your tick.","4":"Pricing rules \u2014 set the margin or markup once, add landed costs, and land prices on psychological endings like \u2026199. Rounding rules are defined on the same page.","5":"Suppliers \u2014 currencies, FX buffers, lead times and minimum order values in one place.","6":"Settings \u2014 the two safety thresholds, manual exchange rates, and current rates with their source.","7":"Automatic runs \u2014 optional scheduled repricing (explicit opt-in) with the full safety net spelled out, plus how long the change journal is kept.","8":"The product's Cost &amp; Margin tab \u2014 supplier and purchase price in the supplier's currency, price lock, and the full \"Why this price?\" breakdown: cost, exchange rate, buffers, rule, VAT and rounding, with the 30-day lowest price (Omnibus reference) and the product's recent price changes."}},"plugin_section":[],"plugin_tags":[132181,11938,4394,230630,62668],"plugin_category":[],"plugin_contributors":[259098],"plugin_business_model":[],"class_list":["post-355757","plugin","type-plugin","status-publish","hentry","plugin_tags-cost-of-goods","plugin_tags-margin","plugin_tags-pricing","plugin_tags-purchase-price","plugin_tags-supplier","plugin_contributors-pihlfelt","plugin_committers-pihlfelt"],"banners":{"banner":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/banner-772x250.png?rev=3658407","banner_2x":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/banner-1544x500.png?rev=3658407","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/icon-128x128.png?rev=3658407","icon_2x":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/icon-256x256.png?rev=3658407","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-1.png?rev=3658407","caption":"Price runs \u2014 preview every change before applying: old and new price, the resulting real margin, and exactly which parameters built each price. Large changes need a per-row tick; every applied run has one-click Undo."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-2.png?rev=3658407","caption":"Import, step 2 \u2014 the supplier's file with auto-detected separator and encoding; map the columns once and the mapping is remembered per supplier."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-3.png?rev=3658407","caption":"Import, step 3 \u2014 every row matched to your products with cost changes, calculated prices and the full calculation breakdown; large changes wait for your tick."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-4.png?rev=3658407","caption":"Pricing rules \u2014 set the margin or markup once, add landed costs, and land prices on psychological endings like \u2026199. Rounding rules are defined on the same page."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-5.png?rev=3658407","caption":"Suppliers \u2014 currencies, FX buffers, lead times and minimum order values in one place."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-6.png?rev=3658407","caption":"Settings \u2014 the two safety thresholds, manual exchange rates, and current rates with their source."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-7.png?rev=3658407","caption":"Automatic runs \u2014 optional scheduled repricing (explicit opt-in) with the full safety net spelled out, plus how long the change journal is kept."},{"src":"https:\/\/ps.w.org\/pihlfelt-cost-margin-pricing-for-woocommerce\/assets\/screenshot-8.png?rev=3658407","caption":"The product's Cost &amp; Margin tab \u2014 supplier and purchase price in the supplier's currency, price lock, and the full \"Why this price?\" breakdown: cost, exchange rate, buffers, rule, VAT and rounding, with the 30-day lowest price (Omnibus reference) and the product's recent price changes."}],"raw_content":"<!--section=description-->\n<p>Set your margin once. Import your supplier's price list. Get finished, well-rounded prices.<\/p>\n\n<p>Cost &amp; Margin Pricing calculates sale prices from your purchase prices \u2014 with support for purchase prices in foreign currencies, daily exchange rates, margin or markup rules, psychological price rounding and a recurring supplier price list import with a full change preview.<\/p>\n\n<p>Built on WooCommerce core fields: the selected purchase cost is always written back to WooCommerce's own Cost of Goods Sold (COGS) field, so Woo's reports, exports and every third-party COGS integration keep working. No parallel cost fields, ever.<\/p>\n\n<p><strong>Safe by design<\/strong><\/p>\n\n<ul>\n<li>Nothing is ever applied without a preview \u2014 you always see the change diff first<\/li>\n<li>Every run is journaled and can be undone with one click<\/li>\n<li>Manually adjusted prices are detected and never silently overwritten<\/li>\n<li>Locked products are always skipped<\/li>\n<\/ul>\n\n<p><strong>EU Omnibus ready<\/strong><\/p>\n\n<p>Marketing a price cut in the EU requires showing the product's lowest price of the last 30 days \u2014 data WooCommerce does not keep. This plugin does: every price change is logged (including ones made outside the plugin), and each product's 30-day lowest price is computed for you. Show it to customers with the <code>[pihlcmp_lowest_price]<\/code> shortcode \u2014 a discreet, theme-friendly line like \"Lowest price last 30 days: 199 kr\" with CSS classes for styling, and a <code>label<\/code> attribute to change or remove the text. Nothing is ever added to your storefront unless you place it yourself.<\/p>\n\n<p><strong>Free version<\/strong><\/p>\n\n<ul>\n<li>One supplier per product with purchase price in any major currency<\/li>\n<li>Supplier column (toggle via Screen Options) and supplier filter in the products list<\/li>\n<li>Daily exchange rates (ECB reference rates, with automatic fallback)<\/li>\n<li>One global margin\/markup rule with price rounding<\/li>\n<li>CSV price list import\/export with change preview<\/li>\n<li>Write-back to WooCommerce core COGS<\/li>\n<li>Change journal with one-click undo<\/li>\n<li>Price change log \u2014 also records price\/cost edits made outside the plugin (who, when, what)<\/li>\n<li>Margin health warnings: products selling below real cost and sales priced below cost<\/li>\n<li>Lowest price last 30 days per product \u2014 the EU Omnibus reference for sale marketing<\/li>\n<li>Optional scheduled runs (monthly) \u2014 explicit opt-in, fully journaled and undoable<\/li>\n<\/ul>\n\n<p><strong>Everything above is included and fully functional \u2014 nothing here is locked, limited or time-restricted.<\/strong><\/p>\n\n<p>A separate commercial plugin, Pihlfelt Cost &amp; Margin Pricing Pro, is available from pihlfelt.se for stores that need more: several suppliers per product with a cost strategy, master-list and Excel import, rules per category\/supplier\/product, margin-based sale prices, a margin floor, extra scheduling intervals with email reports, and margin\/supplier reports. It is a different plugin with its own code \u2014 it is not unlocked from within this one.<\/p>\n\n<h3>External Services<\/h3>\n\n<p>This plugin fetches currency exchange rates from two services: on a daily schedule, when a new currency first needs a rate (e.g. during an import preview), and when you click \"Fetch rates now\" \u2014 and only when you use purchase prices in a currency other than your store currency.<\/p>\n\n<p><strong>European Central Bank (ECB) reference rates<\/strong> \u2014 the primary source. The plugin requests the public daily reference rate file. No personal data and no data about your store is sent; it is a plain file download. Terms: https:\/\/www.ecb.europa.eu\/services\/disclaimer\/html\/index.en.html<\/p>\n\n<p><strong>ExchangeRate-API open endpoint (open.er-api.com)<\/strong> \u2014 used as fallback when the ECB feed is unavailable, and for currencies the ECB does not publish. The request URL contains only your store's base currency code; no personal data and no other data about your store is sent. Terms: https:\/\/www.exchangerate-api.com\/terms \u2014 attribution is shown on the plugin's settings page as required.<\/p>\n\n<p>Rates are indicative reference rates intended for price calculation suggestions, not for payment processing.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20replace%20woocommerce%27s%20cost%20of%20goods%20field%3F\"><h3>Does this replace WooCommerce's Cost of Goods field?<\/h3><\/dt>\n<dd><p>No \u2014 it builds on it. The plugin stores supplier, currency and exchange rate details, and always writes the resulting cost to WooCommerce core's COGS field. Woo's own reports and exports keep working.<\/p><\/dd>\n<dt id=\"can%20prices%20be%20changed%20without%20my%20approval%3F\"><h3>Can prices be changed without my approval?<\/h3><\/dt>\n<dd><p>Only if you explicitly enable scheduled automatic runs in Settings \u2014 and even then, changes above your confirmation threshold are never auto-applied, locked and manually re-priced products are never touched, and every run is journaled and undoable. With the feature off (the default), every rule run and import produces a preview diff that you apply explicitly. Products you have adjusted manually are detected and skipped until you actively release them.<\/p><\/dd>\n<dt id=\"how%20do%20sale%20prices%20work%3F\"><h3>How do sale prices work?<\/h3><\/dt>\n<dd><p>A product's sale price can come from two places, and you always win:<\/p>\n\n<p><em>You<\/em>: type a price in WooCommerce's normal sale price field (e.g. a weekend campaign at a fixed price). The plugin recognizes that this sale is yours and leaves the whole product alone until you remove it.<\/p>\n\n<p>This plugin does not generate sale prices \u2014 it calculates and maintains your ordinary prices. Any sale price on a product is yours, and the plugin leaves that product alone until you remove it.<\/p>\n\n<p>Margin-based sale prices, on-sale flags and scheduled campaigns are part of the separate Pro plugin (see the link below).<\/p><\/dd>\n<dt id=\"what%20do%20blank%20cells%20in%20the%20import%20file%20mean%3F\"><h3>What do blank cells in the import file mean?<\/h3><\/dt>\n<dd><p>Blank always means \"leave unchanged\" \u2014 a file can never accidentally clear something by omitting it. on_sale yes with no dates = on sale until you turn it off (a leftover, already-ended schedule from an old campaign is cleared automatically so \"yes\" means visibly on sale). To explicitly remove a schedule date, put a dash (-) in the date cell. The only required columns are a cost column and one identifier column.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20track%20price%20history%3F\"><h3>Does the plugin track price history?<\/h3><\/dt>\n<dd><p>Yes. Every change the plugin makes is journaled, and price\/cost edits made anywhere else (the product editor, other plugins, the REST API, scheduled sales) are logged too \u2014 visible under \"Recent changes\" on the product's Cost &amp; Margin tab. This also gives you the lowest price of the last 30 days per product, the reference value the EU Omnibus rules require when marketing a price cut. The log starts at plugin activation; earlier history cannot be known.<\/p><\/dd>\n<dt id=\"how%20do%20i%20show%20the%2030-day%20lowest%20price%20to%20customers%3F\"><h3>How do I show the 30-day lowest price to customers?<\/h3><\/dt>\n<dd><p>Place the <code>[pihlcmp_lowest_price]<\/code> shortcode where you want it \u2014 in the product description, a block, or your theme's product template (<code>echo do_shortcode( '[pihlcmp_lowest_price]' );<\/code>). It renders a discreet line: \"Lowest price last 30 days: 199 kr\". Use <code>label=\"Your text:\"<\/code> to change the text, <code>label=\"\"<\/code> for the bare price, and <code>id=\"123\"<\/code> outside a product context. The output carries the CSS classes <code>pihlcmp-lowest-price<\/code>, <code>pihlcmp-lowest-price-label<\/code> and <code>pihlcmp-lowest-price-value<\/code> so you can style every part; no styling is imposed. The plugin never adds anything to your storefront on its own.<\/p><\/dd>\n<dt id=\"how%20many%20suppliers%20can%20i%20have%3F\"><h3>How many suppliers can I have?<\/h3><\/dt>\n<dd><p>As many as you like. Each product is priced from one supplier's cost: pick the supplier on the product's Cost &amp; Margin tab (or in each variation's box), enter the cost and save. To move a product to a different supplier, select the new supplier, enter its cost and tick \"Remove cost row\" \u2014 the old row is replaced in one save. Imports run one supplier's price list at a time, and the products list has a supplier column and filter so you can always see who supplies what.<\/p><\/dd>\n<dt id=\"which%20currencies%20are%20supported%3F\"><h3>Which currencies are supported?<\/h3><\/dt>\n<dd><p>All major currencies via the ECB daily reference rates (about 30), and roughly 130 more via the automatic fallback source. You can also enter exchange rates manually \u2014 manual rates always win.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Calculate sale prices from purchase prices: margin rules, supplier price list import, multi-currency costs and price rounding.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/355757","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=355757"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pihlfelt"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=355757"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=355757"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=355757"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=355757"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=355757"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=355757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}