{
  "$schema": "https://playground.wordpress.net/blueprint-schema.json",
  "landingPage": "/wp-admin/admin.php?page=ai-for-seo",
  "preferredVersions": {
    "php": "8.3",
    "wp": "latest"
  },
  "features": {
    "networking": true
  },
  "steps": [
    {
      "step": "login",
      "username": "admin",
      "password": "password"
    },
    {
      "step": "runPHP",
      "code": "<?php\nrequire_once '/wordpress/wp-load.php';\n\n$option_name = 'ai4seo_playground_demo_instance_id';\n$instance_id = get_option( $option_name, '' );\n\nif ( ! is_string( $instance_id ) || ! preg_match( '/^[a-f0-9-]{36}$/', $instance_id ) ) {\n    update_option( $option_name, wp_generate_uuid4(), false );\n}"
    },
    {
      "step": "runPHP",
      "code": "<?php\nrequire_once '/wordpress/wp-load.php';\nrequire_once ABSPATH . 'wp-admin/includes/image.php';\nif ( ! function_exists( 'wp_insert_post' ) ) {\n    return;\n}\n$marker = '_ai4seo_blueprint_demo';\nupdate_option( 'blogname', 'SOOZ AI for SEO Demo' );\nupdate_option( 'blogdescription', 'Sample content for the SOOZ AI for SEO live preview.' );\n$upload = wp_upload_dir();\nif ( ! empty( $upload['error'] ) ) {\n    return;\n}\n$demo_dir = trailingslashit( $upload['basedir'] ) . 'ai-for-seo-demo';\n$demo_url = trailingslashit( $upload['baseurl'] ) . 'ai-for-seo-demo';\nwp_mkdir_p( $demo_dir );\n$hex = function ( $color ) {\n    $color = ltrim( $color, '#' );\n    return array( hexdec( substr( $color, 0, 2 ) ), hexdec( substr( $color, 2, 2 ) ), hexdec( substr( $color, 4, 2 ) ) );\n};\n$create_png = function ( $filename, $label, $background_hex, $accent_hex ) use ( $demo_dir, $hex ) {\n    $path = trailingslashit( $demo_dir ) . $filename;\n    if ( file_exists( $path ) ) {\n        return $path;\n    }\n    if ( function_exists( 'imagecreatetruecolor' ) && function_exists( 'imagepng' ) ) {\n        $image = imagecreatetruecolor( 1200, 800 );\n        if ( $image ) {\n            $background_rgb = $hex( $background_hex );\n            $accent_rgb = $hex( $accent_hex );\n            $background = imagecolorallocate( $image, $background_rgb[0], $background_rgb[1], $background_rgb[2] );\n            $accent = imagecolorallocate( $image, $accent_rgb[0], $accent_rgb[1], $accent_rgb[2] );\n            $soft_line = imagecolorallocate( $image, 255, 255, 255 );\n            $text = imagecolorallocate( $image, 22, 28, 38 );\n            imagefilledrectangle( $image, 0, 0, 1200, 800, $background );\n            imagefilledrectangle( $image, 0, 620, 1200, 800, $accent );\n            for ( $i = 0; $i < 8; $i++ ) {\n                imageline( $image, 80 + ( $i * 140 ), 120, 170 + ( $i * 140 ), 580, $soft_line );\n            }\n            $lines = explode( '|', wordwrap( $label, 26, '|' ) );\n            $y = 270;\n            foreach ( $lines as $line_text ) {\n                imagestring( $image, 5, 90, $y, $line_text, $text );\n                $y += 34;\n            }\n            imagestring( $image, 3, 90, 700, 'SOOZ AI for SEO demo image', $text );\n            imagepng( $image, $path );\n            imagedestroy( $image );\n        }\n    }\n    if ( ! file_exists( $path ) ) {\n        file_put_contents( $path, base64_decode( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8z8AABQMBgAObK1sAAAAASUVORK5CYII=' ) );\n    }\n    return $path;\n};\n$create_attachment = function ( $filename, $title, $caption, $description, $alt_text, $background_hex, $accent_hex ) use ( $marker, $demo_url, $create_png ) {\n    $path = $create_png( $filename, $title, $background_hex, $accent_hex );\n    $existing = get_posts( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'meta_key' => $marker, 'meta_value' => $filename, 'fields' => 'ids', 'numberposts' => 1 ) );\n    $filetype = wp_check_filetype( $filename, null );\n    $attachment_data = array( 'post_mime_type' => $filetype['type'] ? $filetype['type'] : 'image/png', 'post_title' => $title, 'post_content' => $description, 'post_excerpt' => $caption, 'post_status' => 'inherit', 'guid' => trailingslashit( $demo_url ) . $filename );\n    if ( $existing ) {\n        $attachment_id = (int) $existing[0];\n        $attachment_data['ID'] = $attachment_id;\n        wp_update_post( $attachment_data );\n    } else {\n        $attachment_id = wp_insert_attachment( $attachment_data, $path );\n    }\n    if ( is_wp_error( $attachment_id ) || ! $attachment_id ) {\n        return 0;\n    }\n    update_post_meta( $attachment_id, $marker, $filename );\n    if ( null === $alt_text ) {\n        delete_post_meta( $attachment_id, '_wp_attachment_image_alt' );\n    } else {\n        update_post_meta( $attachment_id, '_wp_attachment_image_alt', $alt_text );\n    }\n    $metadata = wp_generate_attachment_metadata( $attachment_id, $path );\n    if ( ! is_wp_error( $metadata ) && $metadata ) {\n        wp_update_attachment_metadata( $attachment_id, $metadata );\n    }\n    return (int) $attachment_id;\n};\n$image_html = function ( $attachment_id, $caption ) {\n    if ( ! $attachment_id ) {\n        return '';\n    }\n    $image = wp_get_attachment_image( $attachment_id, 'large' );\n    if ( ! $image ) {\n        return '';\n    }\n    return '<figure>' . $image . '<figcaption>' . esc_html( $caption ) . '</figcaption></figure>';\n};\n$find_entry = function ( $post_type, $title ) use ( $marker ) {\n    $key = sanitize_title( $post_type . '-' . $title );\n    $ids = get_posts( array( 'post_type' => $post_type, 'post_status' => 'any', 'meta_key' => $marker, 'meta_value' => $key, 'fields' => 'ids', 'numberposts' => 1 ) );\n    return $ids ? (int) $ids[0] : 0;\n};\n$upsert_entry = function ( $post_type, $title, $content, $excerpt ) use ( $marker, $find_entry ) {\n    $key = sanitize_title( $post_type . '-' . $title );\n    $post_data = array( 'post_type' => $post_type, 'post_title' => $title, 'post_name' => sanitize_title( $title ), 'post_content' => $content, 'post_excerpt' => $excerpt, 'post_status' => 'publish', 'post_author' => 1 );\n    $post_id = $find_entry( $post_type, $title );\n    if ( $post_id ) {\n        $post_data['ID'] = $post_id;\n        wp_update_post( $post_data );\n    } else {\n        $post_id = wp_insert_post( $post_data );\n    }\n    if ( is_wp_error( $post_id ) || ! $post_id ) {\n        return 0;\n    }\n    update_post_meta( $post_id, $marker, $key );\n    return (int) $post_id;\n};\n$metadata_key = defined( 'AI4SEO_POST_META_ACTIVE_METADATA_META_KEY' ) ? AI4SEO_POST_META_ACTIVE_METADATA_META_KEY : 'ai4seo_active_metadata';\n$save_metadata = function ( $post_id, $metadata ) use ( $metadata_key ) {\n    if ( ! $post_id ) {\n        return;\n    }\n    if ( function_exists( 'ai4seo_save_active_metadata_to_postmeta' ) ) {\n        ai4seo_save_active_metadata_to_postmeta( $post_id, $metadata, false );\n        return;\n    }\n    update_post_meta( $post_id, $metadata_key, wp_json_encode( $metadata, JSON_UNESCAPED_UNICODE ) );\n};\n$clear_metadata = function ( $post_id ) use ( $metadata_key ) {\n    if ( $post_id ) {\n        delete_post_meta( $post_id, $metadata_key );\n    }\n};\n$media = array();\n$media['audit'] = $create_attachment( 'sooz-demo-seo-audit.png', 'SEO audit dashboard preview', 'A visual snapshot for an SEO audit workflow.', 'Dashboard style illustration used as sample media for the live preview.', 'Illustration of an SEO audit dashboard with content coverage and metadata status indicators.', 'D9EEF7', 'FFBD82' );\n$media['images'] = $create_attachment( 'sooz-demo-image-optimization.png', 'Product image optimization preview', 'Product image workflow with missing alt text.', 'Preview image for media attribute generation and image SEO workflows.', null, 'E9F5DB', '83C5BE' );\n$media['local'] = $create_attachment( 'sooz-demo-local-search.png', 'Local search landing page preview', '', '', 'Illustration of a local search landing page with map pins and service cards.', 'F3E8FF', 'F6C85F' );\n$media['product'] = $create_attachment( 'sooz-demo-product-page.png', 'Product page search preview', '', '', null, 'E7EEF8', '95A3B3' );\n$page_audit = $upsert_entry( 'page', 'SEO Audit Service', '<h2>Technical SEO audit preview</h2><p>This demo page represents a service page for a technical SEO audit. It gives SOOZ content to analyze, including search intent, service benefits, and conversion context.</p>' . $image_html( $media['audit'], 'Dashboard style illustration for a technical SEO audit.' ) . '<p>The page explains crawl health, indexability, metadata coverage, structured content, and recommendations for improving organic search visibility.</p>', 'Demo service page for SEO audits.' );\n$page_images = $upsert_entry( 'page', 'Product Image Optimization', '<h2>Image SEO for product catalogs</h2><p>This page shows a product image optimization workflow for stores with many media assets. It includes image context for alt text, captions, and descriptions.</p>' . $image_html( $media['images'], 'Product image workflow with intentionally missing alt text.' ) . '<p>Use this content to inspect how media attributes and metadata coverage appear inside the SOOZ live preview.</p>', 'Demo page for product image SEO.' );\n$page_local = $upsert_entry( 'page', 'Local Search Landing Page', '<h2>Local search landing page</h2><p>This landing page targets local search visibility for a service business. It includes location context, customer intent, and service details.</p>' . $image_html( $media['local'], 'Local search illustration with service and location context.' ) . '<p>The page intentionally has no SOOZ metadata so the dashboard can show missing coverage.</p>', 'Demo local SEO landing page.' );\n$post_clicks = $upsert_entry( 'post', 'How Better Meta Descriptions Improve Clicks', '<p>Meta descriptions help searchers decide whether a result matches their intent. Clear summaries can improve click quality and make organic snippets more persuasive.</p><p>This demo post includes complete SOOZ metadata so it can appear as a covered entry in the preview.</p>', 'Demo post about meta descriptions.' );\n$post_alt = $upsert_entry( 'post', 'Image Alt Text Checklist', '<p>Useful alt text describes image content and function without keyword stuffing. A checklist helps teams keep image SEO and accessibility aligned.</p>' . $image_html( $media['product'], 'Product page preview with intentionally incomplete media attributes.' ), 'Demo post about image alt text.' );\n$post_product = $upsert_entry( 'post', 'Preparing Product Pages for Search', '<p>Product pages need clear titles, concise descriptions, helpful images, and metadata that matches purchase intent. This demo post is intentionally left without generated metadata.</p>', 'Demo post for product page SEO.' );\nif ( $page_audit && $media['audit'] ) { set_post_thumbnail( $page_audit, $media['audit'] ); wp_update_post( array( 'ID' => $media['audit'], 'post_parent' => $page_audit ) ); }\nif ( $page_images && $media['images'] ) { set_post_thumbnail( $page_images, $media['images'] ); wp_update_post( array( 'ID' => $media['images'], 'post_parent' => $page_images ) ); }\nif ( $page_local && $media['local'] ) { set_post_thumbnail( $page_local, $media['local'] ); wp_update_post( array( 'ID' => $media['local'], 'post_parent' => $page_local ) ); }\nif ( $post_alt && $media['product'] ) { set_post_thumbnail( $post_alt, $media['product'] ); wp_update_post( array( 'ID' => $media['product'], 'post_parent' => $post_alt ) ); }\n$save_metadata( $page_audit, array( 'focus-keyphrase' => 'technical SEO audit service', 'meta-title' => 'Technical SEO Audit Service for Growing Websites', 'meta-description' => 'Find crawl, content, and metadata issues with a practical SEO audit service built for better organic search performance.', 'keywords' => 'technical SEO audit, SEO service, metadata audit', 'facebook-title' => 'Technical SEO Audit Service', 'facebook-description' => 'See how SOOZ evaluates content and metadata coverage.', 'twitter-title' => 'Technical SEO Audit Service', 'twitter-description' => 'Preview complete metadata coverage in SOOZ.' ) );\n$save_metadata( $page_images, array( 'focus-keyphrase' => 'product image optimization', 'meta-title' => 'Product Image Optimization for Search' ) );\n$clear_metadata( $page_local );\n$save_metadata( $post_clicks, array( 'focus-keyphrase' => 'better meta descriptions', 'meta-title' => 'How Better Meta Descriptions Improve Clicks', 'meta-description' => 'Learn why concise meta descriptions can improve search snippets, visitor intent, and organic click quality.', 'keywords' => 'meta descriptions, organic clicks, SEO snippets', 'facebook-title' => 'Better Meta Descriptions Improve Clicks', 'facebook-description' => 'A complete SOOZ metadata example for preview testing.', 'twitter-title' => 'Better Meta Descriptions Improve Clicks', 'twitter-description' => 'See a covered demo post in SOOZ.' ) );\n$save_metadata( $post_alt, array( 'meta-description' => 'Use this practical alt text checklist to improve image SEO, accessibility, and media library quality.' ) );\n$clear_metadata( $post_product );\nwp_cache_flush();"
    },
    {
      "step": "runPHP",
      "code": "<?php\nrequire_once '/wordpress/wp-load.php';\nif ( function_exists( 'ai4seo_update_setting' ) ) {\n    ai4seo_update_setting( AI4SEO_SETTING_IMAGE_UPLOAD_METHOD, 'base64' );\n    ai4seo_update_setting( AI4SEO_SETTING_ENABLE_EXTERNAL_METADATA_GENERATE_BUTTONS, true );\n    ai4seo_update_setting( AI4SEO_SETTING_ENABLE_EXTERNAL_MEDIA_GENERATE_BUTTONS, true );\n}"
    }
  ]
}
