{
  "$schema": "https://playground.wordpress.net/blueprint-schema.json",
  "landingPage": "/wp-admin/admin.php?page=optistate",
  "preferredVersions": {
    "php": "8.2",
    "wp": "latest"
  },
  "phpExtensionBundles": [
    "kitchen-sink"
  ],
  "features": {
    "networking": true
  },
  "steps": [
    {
      "step": "login",
      "username": "admin",
      "password": "password"
    },
    {
      "step": "installPlugin",
      "pluginData": {
        "resource": "wordpress.org/plugins",
        "slug": "optistate"
      }
    },
    {
      "step": "wp-cli",
      "command": "wp post generate --count=50 --post_type=post --post_status=publish"
    },
    {
      "step": "wp-cli",
      "command": "wp post generate --count=20 --post_type=page --post_status=publish"
    },
    {
      "step": "wp-cli",
      "command": "wp post generate --count=60 --post_type=post --post_status=draft"
    },
    {
      "step": "wp-cli",
      "command": "wp comment generate --count=80 --post_id=1"
    },
    {
      "step": "runPHP",
      "code": "<?php\nrequire '/wordpress/wp-load.php';\nglobal $wpdb;\n\n// === TRASHED POSTS ===\nfor ($i = 0; $i < 80; $i++) {\n    $id = wp_insert_post(array('post_type' => 'post', 'post_status' => 'draft', 'post_title' => 'Trash Post ' . $i));\n    wp_trash_post($id);\n}\nfor ($i = 0; $i < 40; $i++) {\n    $id = wp_insert_post(array('post_type' => 'page', 'post_status' => 'draft', 'post_title' => 'Trash Page ' . $i));\n    wp_trash_post($id);\n}\n\n// === AUTO DRAFTS ===\nfor ($i = 0; $i < 150; $i++) {\n    wp_insert_post(array('post_type' => 'post', 'post_status' => 'inherit', 'post_title' => 'Auto Draft ' . $i));\n}\n\n// === POST REVISIONS (30 posts x 15 revisions = 450) ===\nfor ($p = 0; $p < 30; $p++) {\n    $id = wp_insert_post(array('post_type' => 'post', 'post_status' => 'publish', 'post_title' => 'Revision Post ' . $p, 'post_content' => 'original'));\n    for ($r = 1; $r <= 15; $r++) {\n        wp_update_post(array('ID' => $id, 'post_content' => 'Edit ' . $r . ' of post ' . $p));\n    }\n}\n\n// === SPAM COMMENTS ===\nfor ($i = 0; $i < 120; $i++) {\n    wp_insert_comment(array(\n        'comment_post_ID'      => 2,\n        'comment_content'      => 'Spam comment ' . $i,\n        'comment_approved'     => 'spam',\n        'comment_type'         => '',\n        'comment_author'       => 'Spambot ' . $i,\n        'comment_author_email' => 'spam' . $i . '@fakespam.com'\n    ));\n}\n\n// === TRASHED COMMENTS ===\nfor ($i = 0; $i < 80; $i++) {\n    $cid = wp_insert_comment(array(\n        'comment_post_ID'      => 2,\n        'comment_content'      => 'Trashed comment ' . $i,\n        'comment_approved'     => 1,\n        'comment_author'       => 'Trash Author ' . $i,\n        'comment_author_email' => 'trash' . $i . '@example.com'\n    ));\n    wp_trash_comment($cid);\n}\n\n// === UNAPPROVED COMMENTS ===\nfor ($i = 0; $i < 90; $i++) {\n    wp_insert_comment(array(\n        'comment_post_ID'      => 3,\n        'comment_content'      => 'Pending comment ' . $i,\n        'comment_approved'     => 0,\n        'comment_author'       => 'Pending User ' . $i,\n        'comment_author_email' => 'pending' . $i . '@example.com'\n    ));\n}\n\n// === PINGBACKS ===\nfor ($i = 0; $i < 60; $i++) {\n    wp_insert_comment(array(\n        'comment_post_ID'    => 1,\n        'comment_content'    => 'Pingback from site ' . $i,\n        'comment_approved'   => 1,\n        'comment_type'       => 'pingback',\n        'comment_author'     => 'Pingback ' . $i,\n        'comment_author_url' => 'http://ping-' . $i . '.example.com'\n    ));\n}\n\n// === TRACKBACKS ===\nfor ($i = 0; $i < 60; $i++) {\n    wp_insert_comment(array(\n        'comment_post_ID'    => 1,\n        'comment_content'    => 'Trackback from site ' . $i,\n        'comment_approved'   => 1,\n        'comment_type'       => 'trackback',\n        'comment_author'     => 'Trackback ' . $i,\n        'comment_author_url' => 'http://track-' . $i . '.example.com'\n    ));\n}\n\n// === ORPHANED POST META ===\nfor ($i = 0; $i < 300; $i++) {\n    $wpdb->insert($wpdb->postmeta, array(\n        'post_id'    => 99000 + $i,\n        'meta_key'   => '_orphaned_postmeta_' . $i,\n        'meta_value' => 'orphaned_value_' . $i\n    ));\n}\n\n// === DUPLICATE POST META (80 keys x 3 dupes each) ===\nfor ($i = 0; $i < 80; $i++) {\n    for ($d = 0; $d < 3; $d++) {\n        $wpdb->insert($wpdb->postmeta, array(\n            'post_id'    => 1,\n            'meta_key'   => '_dup_postmeta_' . $i,\n            'meta_value' => 'dup_val_' . $i\n        ));\n    }\n}\n\n// === ORPHANED COMMENT META ===\nfor ($i = 0; $i < 150; $i++) {\n    $wpdb->insert($wpdb->commentmeta, array(\n        'comment_id' => 99000 + $i,\n        'meta_key'   => '_orphaned_commentmeta_' . $i,\n        'meta_value' => 'orphaned_cm_' . $i\n    ));\n}\n\n// === DUPLICATE COMMENT META (60 keys x 3 dupes each) ===\nfor ($i = 0; $i < 60; $i++) {\n    for ($d = 0; $d < 3; $d++) {\n        $wpdb->insert($wpdb->commentmeta, array(\n            'comment_id' => 1,\n            'meta_key'   => '_dup_commentmeta_' . $i,\n            'meta_value' => 'dup_cm_val_' . $i\n        ));\n    }\n}\n\n// === ORPHANED USER META ===\nfor ($i = 0; $i < 100; $i++) {\n    $wpdb->insert($wpdb->usermeta, array(\n        'user_id'    => 99000 + $i,\n        'meta_key'   => '_orphaned_usermeta_' . $i,\n        'meta_value' => 'orphaned_um_' . $i\n    ));\n}\n\n// === DUPLICATE USER META (50 keys x 3 dupes each) ===\nfor ($i = 0; $i < 50; $i++) {\n    for ($d = 0; $d < 3; $d++) {\n        $wpdb->insert($wpdb->usermeta, array(\n            'user_id'    => 1,\n            'meta_key'   => '_dup_usermeta_' . $i,\n            'meta_value' => 'dup_um_val_' . $i\n        ));\n    }\n}\n\n// === DUPLICATE TERM META (50 keys x 3 dupes each) ===\nfor ($i = 0; $i < 50; $i++) {\n    for ($d = 0; $d < 3; $d++) {\n        $wpdb->insert($wpdb->termmeta, array(\n            'term_id'    => 1,\n            'meta_key'   => '_dup_termmeta_' . $i,\n            'meta_value' => 'dup_tm_val_' . $i\n        ));\n    }\n}\n\n// === ORPHANED TERM RELATIONSHIPS ===\nfor ($i = 0; $i < 100; $i++) {\n    $wpdb->insert($wpdb->term_relationships, array(\n        'object_id'        => 88000 + $i,\n        'term_taxonomy_id' => 1\n    ));\n}\n\n// === EXPIRED TRANSIENTS (200 pairs) ===\nfor ($i = 0; $i < 200; $i++) {\n    $wpdb->insert($wpdb->options, array(\n        'option_name'  => '_transient_timeout_expired_' . $i,\n        'option_value' => time() - 86400,\n        'autoload'     => 'no'\n    ));\n    $wpdb->insert($wpdb->options, array(\n        'option_name'  => '_transient_expired_' . $i,\n        'option_value' => str_repeat('cached_junk_', 20),\n        'autoload'     => 'no'\n    ));\n}\n\n// === EXPIRED SITE TRANSIENTS (100 pairs) ===\nfor ($i = 0; $i < 100; $i++) {\n    $wpdb->insert($wpdb->options, array(\n        'option_name'  => '_site_transient_timeout_expired_' . $i,\n        'option_value' => time() - 86400,\n        'autoload'     => 'no'\n    ));\n    $wpdb->insert($wpdb->options, array(\n        'option_name'  => '_site_transient_expired_' . $i,\n        'option_value' => str_repeat('site_cached_junk_', 20),\n        'autoload'     => 'no'\n    ));\n}\n\n// === LARGE AUTOLOADED OPTIONS ===\n$wpdb->insert($wpdb->options, array(\n    'option_name'  => 'big_autoload_300k',\n    'option_value' => str_repeat('Z', 300 * 1024),\n    'autoload'     => 'yes'\n));\n$wpdb->insert($wpdb->options, array(\n    'option_name'  => 'big_cache_60k',\n    'option_value' => str_repeat('Y', 60 * 1024),\n    'autoload'     => 'yes'\n));\n$wpdb->insert($wpdb->options, array(\n    'option_name'  => 'big_autoload_200k_exact',\n    'option_value' => str_repeat('X', 200 * 1024),\n    'autoload'     => 'yes'\n));\n\n// === OEMBED CACHE ===\nfor ($i = 0; $i < 120; $i++) {\n    $url = 'https://www.youtube.com/watch?v=demo' . $i;\n    $cache_key = md5($url);\n    wp_insert_post(array(\n        'post_type'    => 'oembed_cache',\n        'post_status'  => 'publish',\n        'post_title'   => $cache_key,\n        'post_name'    => $cache_key,\n        'post_content' => '<iframe width=560 height=315 src=https://www.youtube.com/embed/demo' . $i . '></iframe>',\n        'post_date'    => date('Y-m-d H:i:s', time() - (86400 * 90))\n    ));\n}\nfor ($i = 0; $i < 60; $i++) {\n    $url = 'https://vimeo.com/demo' . $i;\n    $cache_key = md5($url);\n    wp_insert_post(array(\n        'post_type'    => 'oembed_cache',\n        'post_status'  => 'publish',\n        'post_title'   => $cache_key,\n        'post_name'    => $cache_key,\n        'post_content' => '<iframe src=https://player.vimeo.com/video/demo' . $i . '></iframe>',\n        'post_date'    => date('Y-m-d H:i:s', time() - (86400 * 120))\n    ));\n}\n\n// === EMPTY TAXONOMIES ===\nfor ($i = 0; $i < 80; $i++) {\n    $term = wp_insert_term('Empty Tag ' . $i, 'post_tag');\n    if (!is_wp_error($term)) {\n        $wpdb->update(\n            $wpdb->term_taxonomy,\n            array('count' => 0),\n            array('term_taxonomy_id' => $term['term_taxonomy_id'])\n        );\n    }\n}\nfor ($i = 0; $i < 40; $i++) {\n    $term = wp_insert_term('Empty Category ' . $i, 'category');\n    if (!is_wp_error($term)) {\n        $wpdb->update(\n            $wpdb->term_taxonomy,\n            array('count' => 0),\n            array('term_taxonomy_id' => $term['term_taxonomy_id'])\n        );\n    }\n}\n\n// =================================================================\n// CREATE DATABASE OVERHEAD (fragmentation) – ~4 MB\n// =================================================================\n$overhead_table = $wpdb->prefix . 'optistate_demo_overhead';\n$wpdb->query(\"CREATE TABLE IF NOT EXISTS $overhead_table (\n    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    data TEXT\n) ENGINE=InnoDB\");\n\n// Insert 50,000 rows with ~200 bytes each = ~10 MB data\nfor ($i = 0; $i < 50000; $i++) {\n    $wpdb->insert($overhead_table, array(\n        'data' => str_repeat(sha1(mt_rand()), 5)\n    ));\n}\n\n// Delete half the rows to create fragmentation (free space in tablespace)\n$wpdb->query(\"DELETE FROM $overhead_table WHERE id % 2 = 0\");\n\n// The table now has DATA_FREE > 0, visible in plugin stats.\n// We deliberately do NOT OPTIMIZE this table.\n\n// =================================================================\n// (Removed the OPTIMIZE TABLE loop to preserve overhead)\n// =================================================================\n\nupdate_option('optistate_demo_ready', true);\necho 'Seed complete.';\n"
    }
  ]
}