{"id":371125,"date":"2026-10-07T17:53:48","date_gmt":"2026-10-07T17:53:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/product-category-shipping-for-woocommerce\/"},"modified":"2026-10-07T17:53:17","modified_gmt":"2026-10-07T17:53:17","slug":"product-category-shipping-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/product-category-shipping-for-woocommerce\/","author":23568748,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.5","stable_tag":"1.4.5","tested":"7.1.3","requires":"6.4","requires_php":"7.4","requires_plugins":null,"header_name":"Product Category Shipping for WooCommerce","header_author":"Braxton Moody","header_description":"WooCommerce shipping plugin that charges per product category using flat-rate or tiered-quantity rules. Selected user roles can be offered a cart-wide Free Local Pickup option alongside the configured shipping rates.","assets_banners_color":"b9d4e0","last_updated":"2026-10-07 17:53:17","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/techtankholdings.com\/","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/product-category-shipping\/","header_author_uri":"https:\/\/techtankholdings.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":97,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.5":{"tag":"1.4.5","author":"techtankholdings","date":"2026-10-07 17:53:17","revision":3733142}},"upgrade_notice":{"1.4.1":"<ul>\n<li>Post-review fixes for WordPress.org plugin review. No behaviour changes.<\/li>\n<\/ul>","1.4.0":"<p>Mandatory update for WordPress.org distribution. No behaviour changes from 1.3.0.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3733142,"resolution":"128x128","location":"assets","locale":"","width":256,"height":256},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3733142,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3733142,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-772x250.png":{"filename":"banner-772x250.png","revision":3733142,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.5"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3733142,"resolution":"1","location":"assets","locale":"","width":1009,"height":629},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3733142,"resolution":"2","location":"assets","locale":"","width":1008,"height":960},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3733142,"resolution":"3","location":"assets","locale":"","width":1009,"height":499}},"screenshots":{"1":"Default Shipping Rules \u2014 green cards, one per managed category.","2":"Selected-Role Override Rules \u2014 red cards, inert until roles are configured.","3":"Local Pickup &amp; User Roles \u2014 role picker, labels, diagnostics table.","4":"Category rule configuration \u2014 flat rate or tiered quantity settings per category."}},"plugin_section":[],"plugin_tags":[89,65528,3546,226018,286],"plugin_category":[45],"plugin_contributors":[284872],"plugin_business_model":[],"class_list":["post-371125","plugin","type-plugin","status-publish","hentry","plugin_tags-category","plugin_tags-flat-rate","plugin_tags-shipping","plugin_tags-tiered-shipping","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-techtankholdings","plugin_committers-techtankholdings"],"banners":{"banner":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/banner-772x250.png?rev=3733142","banner_2x":false,"banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/icon.svg?rev=3733142","icon":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/icon.svg?rev=3733142","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/screenshot-1.png?rev=3733142","caption":"Default Shipping Rules \u2014 green cards, one per managed category."},{"src":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/screenshot-2.png?rev=3733142","caption":"Selected-Role Override Rules \u2014 red cards, inert until roles are configured."},{"src":"https:\/\/ps.w.org\/product-category-shipping-for-woocommerce\/assets\/screenshot-3.png?rev=3733142","caption":"Local Pickup &amp; User Roles \u2014 role picker, labels, diagnostics table."}],"raw_content":"<!--section=description-->\n<p>Product Category Shipping lets WooCommerce store owners define shipping rules <strong>per product category<\/strong> instead of per order or per product. Two rule types are available:<\/p>\n\n<ul>\n<li><strong>Flat Rate<\/strong> \u2014 a base charge for the first item, plus an optional per-additional-item charge.<\/li>\n<li><strong>Tiered Quantity<\/strong> \u2014 unlimited min\/max quantity brackets, each with its own price or a \"free\" flag.<\/li>\n<\/ul>\n\n<p>The plugin splits the cart into one WooCommerce shipping package per managed category, so charges are additive and customers see one shipping line per category.<\/p>\n\n<p><strong>Selected roles<\/strong> (e.g. distributors, wholesale accounts) can additionally be offered a cart-wide choice between <strong>Free Local Pickup<\/strong> and the configured shipping charge. When this mode is active the cart is not split \u2014 the customer sees a single combined shipping total alongside the free pickup option.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li>Per-category shipping rules (flat rate or tiered quantity)<\/li>\n<li>Tiered rules support free-shipping thresholds (e.g. \"free when quantity \u2265 6\")<\/li>\n<li>Split-cart mode: one shipping line per category, additive charges<\/li>\n<li>Combined-cart mode for selected roles: Shipping + Free Local Pickup as two cart-wide choices<\/li>\n<li>Role diagnostics table in wp-admin showing exact role keys and user counts<\/li>\n<li>Rate guard prevents third-party \"hide other methods when free shipping applies\" filters from accidentally removing the Local Pickup option<\/li>\n<li>No server round-trips; all calculations run locally on checkout<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 6.4+<\/li>\n<li>PHP 7.4+<\/li>\n<li>WooCommerce 8.0+ (plugin must be active)<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>product-category-shipping<\/code> folder to <code>\/wp-content\/plugins\/<\/code> or install via the WordPress Plugins screen.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> menu in WordPress.<\/li>\n<li>Go to <strong>WooCommerce \u2192 Settings \u2192 Shipping \u2192 Product Category Shipping<\/strong> and add rules for each category you manage.<\/li>\n<li>Optionally, go to <strong>WooCommerce \u2192 Category Shipping<\/strong> to configure Local Pickup roles and labels.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"can%20i%20use%20different%20rule%20types%20for%20different%20categories%3F\"><h3>Can I use different rule types for different categories?<\/h3><\/dt>\n<dd><p>Yes. Each category is configured independently and may use Flat Rate or Tiered Quantity rules.<\/p><\/dd>\n<dt id=\"how%20does%20the%20tiered%20quantity%20mode%20work%3F\"><h3>How does the tiered quantity mode work?<\/h3><\/dt>\n<dd><p>You define quantity brackets such as 1\u20135 = $8, 6\u201311 = $5, 12+ = free. Quantities are counted <strong>per category<\/strong>, not per order. Exact-match tiers (e.g. \"exactly 6\") take priority over range tiers.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20a%20customer%27s%20cart%20quantity%20falls%20outside%20all%20defined%20tiers%3F\"><h3>What happens if a customer's cart quantity falls outside all defined tiers?<\/h3><\/dt>\n<dd><p>Split mode (default): that category package will have no applicable rate and <strong>checkout will be blocked<\/strong> until the customer adjusts quantity or the admin extends the top tier. Combined mode: that category contributes $0 to the total.<\/p><\/dd>\n<dt id=\"how%20do%20i%20enable%20free%20local%20pickup%20for%20specific%20roles%3F\"><h3>How do I enable Free Local Pickup for specific roles?<\/h3><\/dt>\n<dd><p>Go to <strong>WooCommerce \u2192 Category Shipping \u2192 Local Pickup &amp; User Roles<\/strong> and add the desired role keys to the <strong>Pickup Roles<\/strong> field. Role keys are case-sensitive (e.g. <code>Distributor<\/code>, not <code>distributor<\/code>).<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20work%20with%20wpml%20%2F%20polylang%3F\"><h3>Does the plugin work with WPML \/ Polylang?<\/h3><\/dt>\n<dd><p>The plugin loads its own text domain. Translation files (.po\/.mo) can be placed in <code>wp-content\/languages\/plugins\/product-category-shipping-for-woocommerce-{locale}.mo<\/code>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Fixed: duplicate \"Category Shipping\" submenu entry appearing under WooCommerce.\nRoot cause: the admin class was instantiated on <code>plugins_loaded<\/code>, which fires on every\nrequest and could run twice during WooCommerce's own boot sequence. Changed to\n  add_action('admin_menu') at priority 20 so it registers exactly once.<\/li>\n<li>Fixed: admin settings page rendering raw HTML markup as plain text. Root cause:\n  render_page() passed its buffered output through <code>esc_html()<\/code> before echoing it,\nconverting <code>&lt;<\/code>\/<code>&gt;<\/code> to <code>&amp;lt;<\/code>\/<code>&amp;gt;<\/code>. Removed the stray <code>esc_html()<\/code> call.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Post-review fixes: changed text domain to product-category-shipping-for-woocommerce;\nreplaced inline CSS\/JS with wp_enqueue_style\/script + external admin.css\/admin.js;\nremoved Tested up to from PHP header; added Requires Plugins header;\nremoved WordPress.org assets from plugin zip<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li><p>Rebranded: changed text domain to product-category-shipping-for-woocommerce;\nreplaced inline CSS\/JS with wp_enqueue_style\/script + external admin.css\/admin.js;\nremoved Tested up to from PHP header; added Requires Plugins header;\nremoved WordPress.org assets from plugin zip<\/p><\/li>\n<li><p>Rebranded to \"Product Category Shipping for WooCommerce\"<\/p><\/li>\n<li>Updated header fields for WordPress.org compatibility (Tested up to 7.1, WC 9.3)<\/li>\n<li>Added <code>Requires at least<\/code>, <code>Requires PHP<\/code>, <code>WC requires at least<\/code>, <code>WC tested up to<\/code> header fields<\/li>\n<li>Added translation infrastructure (<code>load_plugin_textdomain<\/code>, languages directory)<\/li>\n<li>Internal: renamed main plugin file; no functional changes<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Added Selected-Role Override Rules \u2014 a second, independent rule set that fully replaces the default rules for a category when the customer's role is in <code>pickup_roles<\/code>.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Fixed role keys being lowercased by <code>sanitize_key()<\/code>, which silently dropped custom roles on every save.<\/li>\n<li>Added role diagnostics table to the admin screen.<\/li>\n<li>Added rate guard at priority 99999 to re-insert both combined-mode rates so a third-party \"hide other methods when free shipping exists\" filter cannot remove one.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Role-gated free Local Pickup with combined cart-wide rate for selected roles.<\/li>\n<li>Fixed double-counting for products assigned to two managed categories.<\/li>\n<li>Made shipping rate IDs unique across all categories.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Per-category rules, cart split, admin settings page.<\/li>\n<\/ul>","raw_excerpt":"WooCommerce shipping per product category \u2014 flat rate or tiered-quantity rules, plus Free Local Pickup for selected roles.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/371125","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=371125"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/techtankholdings"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=371125"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=371125"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=371125"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=371125"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=371125"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=371125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}