{
  "$schema": "https://playground.wordpress.net/blueprint-schema.json",
  "meta": {
    "title": "Tiered Pricing Table for WooCommerce",
    "description": "Demo store with six products showing fixed quantity tiers in the table, blocks, options, dropdown and horizontal layouts, plus a variable product, with a guided tour.",
    "author": "bycrik"
  },
  "landingPage": "/product/t-shirt-with-logo/",
  "preferredVersions": {
    "php": "8.2",
    "wp": "latest"
  },
  "features": {
    "networking": true
  },
  "login": true,
  "steps": [
    {
      "step": "defineWpConfigConsts",
      "consts": {
        "TPT_PLAYGROUND": true
      }
    },
    {
      "step": "installTheme",
      "themeData": {
        "resource": "wordpress.org/themes",
        "slug": "storefront"
      },
      "options": {
        "activate": true
      }
    },
    {
      "step": "installPlugin",
      "pluginData": {
        "resource": "wordpress.org/plugins",
        "slug": "woocommerce"
      },
      "options": {
        "activate": true
      }
    },
    {
      "step": "installPlugin",
      "pluginData": {
        "resource": "wordpress.org/plugins",
        "slug": "tier-pricing-table"
      },
      "options": {
        "activate": true
      }
    },
    {
      "step": "mkdir",
      "path": "/wordpress/wp-content/mu-plugins"
    },
    {
      "step": "writeFile",
      "path": "/wordpress/wp-content/mu-plugins/tpt-playground-demo.php",
      "data": "<?php\n/**\n * Plugin Name: Tiered Pricing Table – Playground demo guide\n * Description: Guidance layer for the WordPress Playground demo. Does nothing unless TPT_PLAYGROUND is defined by the blueprint.\n */\nif ( ! defined( 'TPT_PLAYGROUND' ) || ! TPT_PLAYGROUND ) { return; }\n\n// 0. No post-activation redirect to the welcome page: the first admin click must land where the visitor pointed it.\n$tpt_demo_no_redirect = function () { if ( function_exists( 'tpt_fs' ) ) { tpt_fs()->add_filter( 'redirect_on_activation', '__return_false' ); } };\nadd_action( 'tpt_fs_loaded', $tpt_demo_no_redirect );\nadd_action( 'plugins_loaded', $tpt_demo_no_redirect, 20 );\nadd_filter( 'fs_redirect_on_activation_tier-pricing-table', '__return_false' );\n\nfunction tpt_demo_ids(): array { return (array) get_option( 'tpt_demo_ids', array() ); }\nfunction tpt_demo_link( string $key ): string { $ids = tpt_demo_ids(); return ! empty( $ids[ $key ] ) ? get_permalink( (int) $ids[ $key ] ) : home_url( '/shop/' ); }\nfunction tpt_demo_edit_link( int $productId ): string { return admin_url( 'post.php?post=' . $productId . '&action=edit&tpt_tab=1' ); }\nfunction tpt_demo_settings_link(): string { return admin_url( 'admin.php?page=wc-settings&tab=tiered_pricing_table_settings' ); }\n\n// 1. Front-end banner with a guided tour.\nadd_action( 'wp_body_open', function () {\n\tif ( is_admin() ) { return; }\n\t$ids   = tpt_demo_ids();\n\t$items = array(\n\t\tarray( tpt_demo_link( 'table' ), 'Table: change the quantity', is_product() && get_the_ID() === (int) ( $ids['table'] ?? 0 ) ),\n\t\tarray( tpt_demo_link( 'blocks' ), 'Blocks layout', is_product() && get_the_ID() === (int) ( $ids['blocks'] ?? 0 ) ),\n\t\tarray( tpt_demo_link( 'options' ), 'Options layout', is_product() && get_the_ID() === (int) ( $ids['options'] ?? 0 ) ),\n\t\tarray( tpt_demo_link( 'dropdown' ), 'Dropdown layout', is_product() && get_the_ID() === (int) ( $ids['dropdown'] ?? 0 ) ),\n\t\tarray( tpt_demo_link( 'horizontal' ), 'Horizontal table', is_product() && get_the_ID() === (int) ( $ids['horizontal'] ?? 0 ) ),\n\t\tarray( tpt_demo_link( 'variable' ), 'Variable product', is_product() && get_the_ID() === (int) ( $ids['variable'] ?? 0 ) ),\n\t\tarray( tpt_demo_edit_link( (int) ( $ids['table'] ?? 0 ) ), 'Edit tiers', false ),\n\t\tarray( tpt_demo_settings_link(), 'Settings', false ),\n\t);\n\t?>\n\t<style>\n\t\t.tpt-demo-bar{background:#1e293b;color:#e2e8f0;font:14px/1.5 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;padding:10px 20px;display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center;position:relative;z-index:5}\n\t\t.tpt-demo-bar strong{color:#fff;margin-right:4px}\n\t\t.tpt-demo-bar a{color:#c4b5fd;text-decoration:none;white-space:nowrap}\n\t\t.tpt-demo-bar a:hover{color:#fff;text-decoration:underline}\n\t\t.tpt-demo-bar a.is-current{color:#fff;font-weight:600;border-bottom:2px solid #a78bfa}\n\t\t.tpt-demo-bar a.tpt-demo-contact{margin-left:auto;color:#fff;border:1px solid #64748b;border-radius:4px;padding:2px 10px}\n\t\t.tpt-demo-bar a.tpt-demo-contact:hover{background:#334155;text-decoration:none}\n\t\t.tpt-demo-bar button{background:none;border:1px solid #475569;color:#cbd5e1;border-radius:4px;padding:2px 8px;cursor:pointer}\n\t\t.tpt-demo-edit{display:inline-block;margin:14px 0 4px;padding:8px 14px;border:1px solid #96598a;border-radius:4px;color:#96598a!important;font-weight:600;text-decoration:none!important}\n\t\t.tpt-demo-edit:hover{background:#96598a;color:#fff!important}\n\t</style>\n\t<div class=\"tpt-demo-bar\" id=\"tpt-demo-bar\">\n\t\t<strong>Demo store, try:</strong>\n\t\t<?php foreach ( $items as $i ) : ?><a href=\"<?php echo esc_url( $i[0] ); ?>\" class=\"<?php echo $i[2] ? 'is-current' : ''; ?>\"><?php echo esc_html( $i[1] ); ?></a><?php endforeach; ?>\n\t\t<a href=\"https://tiered-pricing.com/contact-us/?utm_source=playground&amp;utm_medium=demo&amp;utm_campaign=banner\" target=\"_blank\" rel=\"noopener\" class=\"tpt-demo-contact\">Questions? Contact us &#8599;</a>\n\t\t<button type=\"button\" onclick=\"document.getElementById('tpt-demo-bar').remove();sessionStorage.setItem('tptDemoBar','off')\" aria-label=\"Hide\">Hide</button>\n\t</div>\n\t<script>if(sessionStorage.getItem('tptDemoBar')==='off'){var b=document.getElementById('tpt-demo-bar');if(b){b.remove();}}</script>\n\t<?php\n} );\n\n// 2. \"Edit this product's tiers\" under the add-to-cart form on product pages.\nadd_action( 'woocommerce_single_product_summary', function () {\n\tglobal $product;\n\tif ( ! $product instanceof WC_Product ) { return; }\n\t$id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id();\n\techo '<a class=\"tpt-demo-edit\" href=\"' . esc_url( tpt_demo_edit_link( $id ) ) . '\">Edit this product&rsquo;s tiers &rarr;</a>';\n}, 35 );\n\n// 3. Product editor: open the Tiered Pricing tab and explain what to do.\nadd_action( 'admin_footer-post.php', function () {\n\tif ( empty( $_GET['tpt_tab'] ) ) { return; }\n\techo '<script>jQuery(function($){var r=$(\".tiered-pricing-rules-form\").first();if(r.length){$(\"html,body\").animate({scrollTop:r.offset().top-120},400);r.css({outline:\"2px solid #96598a\",outlineOffset:\"8px\",borderRadius:\"4px\"});}});</script>';\n} );\nadd_action( 'admin_notices', function () {\n\t$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;\n\tif ( ! $screen || 'product' !== $screen->id || empty( $_GET['tpt_tab'] ) ) { return; }\n\techo '<div class=\"notice notice-info tpt-demo-notice\"><p><strong>Demo:</strong> the highlighted <em>Tiered price</em> rows in the General tab are this product&rsquo;s quantity breaks. Change a price, add a row with <em>New tier</em>, click <em>Update</em>, then <a href=\"' . esc_url( get_permalink( (int) $_GET['post'] ) ) . '\">view the product</a> to see the table change.</p></div>';\n} );\n\n// 4. Settings page: what the premium version adds.\nadd_action( 'woocommerce_settings_tiered_pricing_table_settings', function () {\n\techo '<div class=\"notice notice-info inline tpt-demo-notice\" style=\"margin:12px 0 20px;padding:12px 16px\"><p style=\"margin:0 0 6px\"><strong>This demo runs the free version.</strong> Premium adds role-based and customer-specific prices, global pricing rules for categories and brands, minimum, maximum and step quantities, request-a-quote, catalog prices, cart upsells and CSV import/export.</p><p style=\"margin:0\"><a href=\"https://tiered-pricing.com/?utm_source=playground&amp;utm_medium=demo&amp;utm_campaign=settings-note\" target=\"_blank\" rel=\"noopener\">See the premium features and pricing &rarr;</a> &nbsp;|&nbsp; <a href=\"https://tiered-pricing.com/contact-us/?utm_source=playground&amp;utm_medium=demo&amp;utm_campaign=settings-note\" target=\"_blank\" rel=\"noopener\">Questions? Contact us</a></p></div>';\n}, 5 );\n\n// 5. Admin bar shortcut back to the guided tour.\nadd_action( 'admin_bar_menu', function ( $bar ) {\n\t$bar->add_node( array( 'id' => 'tpt-demo', 'title' => 'Demo guide', 'href' => tpt_demo_link( 'table' ) ) );\n}, 100 );\n\n// 6. Quiet admin: no WooCommerce activity panel, inbox, marketing, task lists, store alerts or payment promos.\nadd_filter( 'woocommerce_admin_features', function ( $features ) {\n\t$off = array( 'activity-panels', 'remote-inbox-notifications', 'marketing', 'store-alerts', 'launch-your-store', 'wc-pay-promotion', 'wc-pay-welcome-page', 'shipping-label-banner', 'mobile-app-banner', 'customer-effort-score-tracks', 'onboarding-tasks', 'homescreen' );\n\treturn array_values( array_diff( (array) $features, $off ) );\n} );\nadd_filter( 'woocommerce_show_admin_notice', '__return_false' );\nadd_filter( 'woocommerce_helper_suppress_admin_notices', '__return_true' );\nremove_action( 'admin_notices', 'update_nag', 3 );\nremove_action( 'admin_notices', 'maintenance_nag', 10 );\nadd_filter( 'pre_site_transient_update_core', '__return_null' );\n// Empty dashboard: no news, events, activity or WooCommerce status widgets.\nadd_action( 'wp_dashboard_setup', function () { $GLOBALS['wp_meta_boxes']['dashboard'] = array(); }, 999 );\nadd_action( 'load-index.php', function () { update_user_meta( get_current_user_id(), 'show_welcome_panel', 0 ); } );\nadd_action( 'admin_menu', function () {\n\tremove_menu_page( 'edit-comments.php' );\n\tremove_menu_page( 'woocommerce-marketing' );\n\tremove_submenu_page( 'index.php', 'update-core.php' );\n\tremove_submenu_page( 'woocommerce', 'tiered-pricing-table-account' );\n\tremove_submenu_page( 'woocommerce', 'tiered-pricing-table-contact-us' );\n\tremove_submenu_page( 'woocommerce', 'tiered-pricing-table-welcome' );\n\tremove_submenu_page( 'woocommerce', 'wc-admin' );\n}, 999 );\nadd_action( 'admin_head', function () {\n\techo '<style>\n\t\t.notice:not(.tpt-demo-notice), .updated:not(.tpt-demo-notice), #welcome-panel, .woocommerce-layout__header .woocommerce-layout__activity-panel, .woocommerce-layout__header-heading + div, .update-nag, .fs-notice, #wpfooter, #screen-meta-links,\n\t\t#wp-admin-bar-updates, #wp-admin-bar-comments, #wp-admin-bar-wp-logo, #wp-admin-bar-site-status, #wp-admin-bar-woocommerce-site-visibility-badge,\n\t\t#woocommerce-activity-panel, .woocommerce-layout__activity-panel, .woocommerce-layout__header-tasks-reminder-bar, .woocommerce-store-alerts,\n\t\t#adminmenu .awaiting-mod, #adminmenu .update-plugins, #adminmenu .wp-ui-notification, .woocommerce-payments-badge,\n\t\ta[href*=\"page=tiered-pricing-table-account\"], a[href*=\"page=tiered-pricing-table-contact-us\"], .tpt-unread-badge { display: none !important; }\n\t</style>';\n} );\n// Front end: quiet admin bar, full-width product pages.\nadd_action( 'wp_head', function () { echo '<style>#wp-admin-bar-updates, #wp-admin-bar-comments, #wp-admin-bar-wp-logo, #wp-admin-bar-woocommerce-site-visibility-badge { display: none !important; }</style>'; } );\nadd_action( 'wp', function () {\n\tremove_action( 'storefront_sidebar', 'storefront_get_sidebar', 10 );\n\tadd_filter( 'body_class', function ( $c ) { $c[] = 'storefront-full-width-content'; return $c; } );\n} );\n"
    },
    {
      "step": "runPHP",
      "code": "<?php\nrequire_once '/wordpress/wp-load.php';\n// Store basics: no coming-soon wall, pretty permalinks, USD, WooCommerce onboarding skipped, no first-visit redirects.\nupdate_option( 'woocommerce_coming_soon', 'no' );\nupdate_option( 'woocommerce_currency', 'USD' );\nupdate_option( 'woocommerce_default_country', 'US:CA' );\nupdate_option( 'woocommerce_calc_taxes', 'no' );\nupdate_option( 'woocommerce_onboarding_profile', array( 'skipped' => true ) );\nupdate_option( 'woocommerce_task_list_hidden', 'yes' );\nupdate_option( 'woocommerce_extended_task_list_hidden', 'yes' );\nupdate_option( 'woocommerce_show_marketplace_suggestions', 'no' );\nupdate_option( 'blogname', 'Tiered Pricing Demo' );\nupdate_option( 'blogdescription', 'Buy more, pay less' );\ndelete_transient( '_wc_activation_redirect' );\ndelete_option( 'tpt_plugin_do_activation_redirect' );\nupdate_user_meta( 1, 'show_welcome_panel', 0 );\nif ( class_exists( 'WC_Install' ) ) { WC_Install::create_pages(); }\nwp_delete_post( 1, true ); wp_delete_post( 2, true ); wp_delete_comment( 1, true );\n\n// Tiered Pricing Table settings (free features only). Option id without the tier_pricing_table_ prefix.\nforeach ( array(\n\t'display'                     => 'yes',\n\t'display_type'                => 'table',\n\t'position_hook'               => 'woocommerce_before_add_to_cart_button',\n\t'table_title'                 => 'Buy more, pay less',\n\t'quantity_type'               => 'range',\n\t'selected_quantity_color'     => '#7f54b3',\n\t'show_discount_column'        => 'yes',\n\t'head_quantity_text'          => 'Quantity',\n\t'head_discount_text'          => 'Discount',\n\t'head_price_text'             => 'Price each',\n\t'table_quantity_measurement'  => array( 'singular' => 'piece', 'plural' => 'pieces' ),\n\t'blocks_quantity_measurement' => array( 'singular' => 'piece', 'plural' => 'pieces' ),\n\t'pricing_table_style'         => 'default',\n\t'pricing_blocks_style'        => 'default',\n\t'pricing_options_style'       => 'default',\n\t'options_show_original_product_price' => 'yes',\n\t'options_show_default_option' => 'yes',\n\t'tooltip_color'               => '#7f54b3',\n\t'update_price_on_product_page' => 'yes',\n\t'show_tiered_price_as_discount' => 'yes',\n\t'round_price'                 => 'yes',\n\t'cache_enabled'               => 'yes',\n) as $id => $value ) { update_option( 'tier_pricing_table_' . $id, $value ); }\n\n$catId = wp_insert_term( 'Apparel', 'product_cat' );\n$catId = is_wp_error( $catId ) ? (int) get_term_by( 'slug', 'apparel', 'product_cat' )->term_id : (int) $catId['term_id'];\n$image = function ( $url, $postId ) {\n\tif ( ! function_exists( 'media_sideload_image' ) ) { require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; }\n\t$id = media_sideload_image( $url, $postId, null, 'id' );\n\tif ( ! is_wp_error( $id ) ) { set_post_thumbnail( $postId, $id ); }\n};\n// Fixed-price tiers only: percentage tiers are a premium feature.\n$tiers = function ( $id, array $rules, $layout = 'default' ) {\n\tupdate_post_meta( $id, '_fixed_price_rules', $rules );\n\tupdate_post_meta( $id, '_percentage_price_rules', array() );\n\tupdate_post_meta( $id, '_tiered_price_rules_type', 'fixed' );\n\tupdate_post_meta( $id, '_tiered_pricing_template', $layout );\n};\n$simple = function ( $name, $price, $desc, $img ) use ( $catId, $image ) {\n\t$p = new WC_Product_Simple();\n\t$p->set_name( $name ); $p->set_regular_price( $price ); $p->set_short_description( $desc );\n\t$p->set_category_ids( array( $catId ) ); $p->set_manage_stock( false ); $p->set_status( 'publish' );\n\t$id = $p->save(); $image( $img, $id ); return $id;\n};\n$base = 'https://woocommercecore.mystagingwebsite.com/wp-content/uploads/2017/12/';\n$demo = array();\n$id = $simple( 'T-Shirt with Logo', 18, 'Heavyweight cotton tee. Order by the dozen for crews, events and uniforms.', $base . 't-shirt-with-logo-1.jpg' );\n$tiers( $id, array( 10 => 16, 25 => 14.5, 50 => 12, 100 => 10 ), 'table' ); $demo['table'] = $id;\n$id = $simple( 'Cap', 18, 'Six-panel cotton cap with an adjustable strap.', $base . 'cap-2.jpg' );\n$tiers( $id, array( 12 => 16, 36 => 14, 72 => 12 ), 'blocks' ); $demo['blocks'] = $id;\n$id = $simple( 'Beanie', 20, 'Knit beanie, one size. Tiers shown as selectable options.', $base . 'beanie-2.jpg' );\n$tiers( $id, array( 6 => 18, 12 => 17, 24 => 15 ), 'options' ); $demo['options'] = $id;\n$id = $simple( 'Belt', 65, 'Full-grain leather belt with a brushed steel buckle. Tiers in a dropdown.', $base . 'belt-2.jpg' );\n$tiers( $id, array( 3 => 60, 6 => 55, 12 => 50 ), 'dropdown' ); $demo['dropdown'] = $id;\n$id = $simple( 'Hoodie with Logo', 45, 'Fleece hoodie with a printed logo. Tiers in a horizontal table.', $base . 'hoodie-with-logo-2.jpg' );\n$tiers( $id, array( 5 => 40, 10 => 36, 25 => 32 ), 'horizontal-table' ); $demo['horizontal'] = $id;\n// Variable product: each variation carries its own fixed tiers.\n$v = new WC_Product_Variable();\n$v->set_name( 'V-Neck T-Shirt' ); $v->set_short_description( 'Soft V-neck tee in three colours. Every colour has its own quantity breaks.' );\n$v->set_category_ids( array( $catId ) ); $v->set_status( 'publish' );\n$attr = new WC_Product_Attribute(); $attr->set_name( 'Color' ); $attr->set_options( array( 'Blue', 'Green', 'Red' ) ); $attr->set_visible( true ); $attr->set_variation( true );\n$v->set_attributes( array( $attr ) ); $vid = $v->save(); $image( $base . 'vneck-tee-2.jpg', $vid );\nforeach ( array( 'Blue' => array( 10 => 16, 25 => 14, 50 => 12 ), 'Green' => array( 10 => 15.5, 25 => 13.5, 50 => 11.5 ), 'Red' => array( 10 => 17, 25 => 15 ) ) as $color => $rules ) {\n\t$var = new WC_Product_Variation(); $var->set_parent_id( $vid ); $var->set_attributes( array( 'color' => $color ) ); $var->set_regular_price( 18 ); $var->set_status( 'publish' );\n\t$tiers( $var->save(), $rules );\n}\nWC_Product_Variable::sync( $vid ); $demo['variable'] = $vid;\nupdate_option( 'tpt_demo_ids', $demo );\nupdate_option( 'permalink_structure', '/%postname%/' );\nflush_rewrite_rules();\necho 'seeded';\n"
    }
  ]
}