{
    "name": "Voxycure Framework Developer Resources",
    "description": "Developer documentation for building WordPress blocks, fields, post types, taxonomies, option pages, and WooCommerce integrations with Voxycure Framework.",
    "version": "2.0.0",
    "updated": "2026-08-16",
    "documents": [
        {
            "url": "https://framework.voxycureinfotech.com/",
            "title": "Voxycure Framework Developer Resources",
            "group": "Getting started",
            "description": "A lightweight, code-first toolkit for building WordPress themes with dynamic blocks, structured fields, content types, and settings pages.",
            "sections": [
                {
                    "id": "what-it-does",
                    "title": "What the framework does",
                    "text": "Voxycure provides a single PHP registry and shared editor controls. Your theme or companion plugin owns every definition; WordPress owns every saved value.\n01Define in codeReviewable definitions that move with Git and deployments.\n02Store nativelyBlock attributes, post meta, and options—no framework tables.\n03Render in PHPSecure dynamic templates controlled by the developer."
                },
                {
                    "id": "storage",
                    "title": "Where data is stored",
                    "text": "FeatureDefinitionSaved values\nBlocksTheme/plugin PHPpost_content block attributes\nDocument fieldsTheme/plugin PHPRegistered post meta\nOption pagesTheme/plugin PHPwp_options\nPost types & taxonomiesTheme/plugin PHPNative WordPress content tables"
                },
                {
                    "id": "requirements",
                    "title": "Requirements",
                    "text": "PHP 8.0 or newer\nWordPress 6.0 or newer\nA block theme, classic theme, or companion plugin for registrations\nNo Node.js or asset build requiredOfficial Voxycure releases already contain the compiled editor assets. Theme and plugin developers should not edit build/, src/, or any file inside Voxycure Framework. Put project definitions, PHP templates, and styles in your own theme or companion plugin; plugin updates can replace every Voxycure file."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/getting-started/installation",
            "title": "Installation",
            "group": "Getting started",
            "description": "Install the framework and place project definitions in code that loads after the plugin.",
            "sections": [
                {
                    "id": "install",
                    "title": "Install from WordPress.org",
                    "text": "Install the official plugin directly from the Voxycure Framework page on WordPress.org.\nIn WordPress, open Plugins → Add New Plugin.\nSearch for Voxycure Framework.\nSelect Install Now, then Activate.\nCreate a registration file in your theme or companion plugin.\nRecommendedFor reusable projects, keep registrations in a small companion plugin so changing themes does not unregister content types."
                },
                {
                    "id": "manual-install",
                    "title": "Manual installation",
                    "text": "Download a packaged Voxycure release, upload its voxycure-framework folder to wp-content/plugins/, and activate it in WordPress. Do not install the unbuilt source repository on a client site and do not run npm commands inside the installed plugin."
                },
                {
                    "id": "theme-file",
                    "title": "Load a theme registration file",
                    "text": "PHPCopy// functions.php\nrequire_once get_theme_file_path('inc/voxycure.php');"
                },
                {
                    "id": "verify",
                    "title": "Verify the installation",
                    "text": "There is intentionally no Voxycure builder menu. Add a small registration, refresh WordPress, and confirm the content type or block appears in its native editor."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/getting-started/first-project",
            "title": "Build your first project feature",
            "group": "Getting started",
            "description": "Register a post type, attach structured fields, and read the saved values in a theme template.",
            "sections": [
                {
                    "id": "register",
                    "title": "1. Register the post type and fields",
                    "text": "Place this complete code in inc/voxycure.php, then load that file from the theme’s functions.php.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_post_type('project', [\n 'name' => 'Projects',\n 'singular_name' => 'Project',\n 'show_in_rest' => true,\n 'supports' => ['title', 'editor', 'thumbnail'],\n ]);\n \n $registry->register_field_group('project-details', [\n 'name' => 'Project details',\n 'post_types' => ['project'],\n 'fields' => [\n ['field_key' => 'client_name', 'label' => 'Client', 'type' => 'text'],\n ['field_key' => 'launch_date', 'label' => 'Launch date', 'type' => 'date'],\n ],\n ]);\n});"
                },
                {
                    "id": "edit",
                    "title": "2. Edit and save",
                    "text": "Create a Project in WordPress. The document settings panel is loaded only in the block editor and only for the targeted post type. Saving the post sends the registered meta through the WordPress REST API."
                },
                {
                    "id": "render",
                    "title": "3. Render the values",
                    "text": "PHPCopy<p class=\"project-client\">\n <?= esc_html(voxycure_get_field('client_name')) ?>\n</p>"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/getting-started/architecture",
            "title": "Architecture and lifecycle",
            "group": "Getting started",
            "description": "Understand when definitions load, when WordPress registers them, and how content is persisted.",
            "sections": [
                {
                    "id": "lifecycle",
                    "title": "Request lifecycle",
                    "text": "Plugin bootstrapCore services and optional integration hooks load.\nvoxycure/registerYour definitions are collected once per request.\nWordPress initContent types, blocks, and post meta are registered.\nEditor or frontendOnly the relevant adapter, assets, and definitions run for that screen."
                },
                {
                    "id": "performance",
                    "title": "Performance model",
                    "text": "Definitions remain in memory for the request. There are no definition-table queries. Block output caching is disabled until a developer sets a positive TTL."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/core/registry",
            "title": "Registry API",
            "group": "Core concepts",
            "description": "The registry is the public entry point for every framework definition.",
            "sections": [
                {
                    "id": "where-it-comes-from",
                    "title": "Where does $registry come from?",
                    "text": "You do not create $registry. Voxycure creates one shared Registry object and passes it as the first argument when the voxycure/register WordPress action runs.\nPHPCopy<?php\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n // $registry is available only inside this callback.\n $registry->register_post_type('project', [\n 'name' => 'Projects',\n ]);\n});Read it in plain Englishadd_action() means: “When Voxycure announces that registration is open, run this function.” Voxycure supplies the registry object; the variable name $registry is chosen by you."
                },
                {
                    "id": "theme-loading",
                    "title": "Load the callback from a theme",
                    "text": "Create inc/voxycure.php in the active theme and require it once from functions.php. WordPress loads functions.php automatically; that file loads your definitions.\nPHPCopy// functions.php\ndefined('ABSPATH') || exit;\n\nrequire_once get_theme_file_path('inc/voxycure.php');If Voxycure is inactive, the action is never fired and the callback does nothing. The theme must not call new Registry()."
                },
                {
                    "id": "methods",
                    "title": "Available methods",
                    "text": "MethodPurpose\nregister_post_type($slug, $definition)Register a WordPress post type.\nregister_taxonomy($slug, $definition)Register a taxonomy and connect post types.\nregister_block($id, $definition)Register a dynamic PHP block.\nregister_field_group($id, $definition)Attach fields to WordPress documents or a supported integration such as WooCommerce products.\nregister_option_page($slug, $definition)Create a code-defined settings screen."
                },
                {
                    "id": "organization",
                    "title": "Organize a larger project",
                    "text": "TEXTCopyyour-theme/\n├── functions.php\n├── inc/\n│ ├── voxycure.php\n│ └── voxycure/\n│ ├── post-types.php\n│ ├── taxonomies.php\n│ ├── fields.php\n│ ├── blocks.php\n│ └── options.php\n└── blocks/\n └── hero/\n ├── render.php\n └── style.css"
                },
                {
                    "id": "official-hook",
                    "title": "Official WordPress reference",
                    "text": "WordPress: add_action() explains how callbacks receive values passed by an action. WordPress: get_theme_file_path() explains child-theme-aware file paths."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/content/post-types",
            "title": "Post types",
            "group": "Content types",
            "description": "Register editor-ready content types using familiar WordPress arguments.",
            "sections": [
                {
                    "id": "example",
                    "title": "Complete example",
                    "text": "PHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_post_type('project', [\n 'name' => 'Projects',\n 'singular_name' => 'Project',\n 'show_in_rest' => true,\n 'supports' => ['title', 'editor', 'thumbnail'],\n ]);\n});"
                },
                {
                    "id": "arguments",
                    "title": "Definition arguments",
                    "text": "KeyTypeDefault / purpose\nnamestringPlural label derived from the slug.\nsingular_namestringFalls back to name.\npublicbooleantrue\nshow_uibooleantrue\nshow_in_restbooleantrue; required for the block editor.\nsupportsstring[]title and editor.\nhas_archiveboolean|stringtrue\nrewrite_slugstringThe post type slug.\nargsarrayOverrides or adds native WordPress arguments."
                },
                {
                    "id": "advanced",
                    "title": "Pass current WordPress arguments",
                    "text": "This is a complete inc/voxycure.php file. Put advanced native arguments inside args.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_post_type('event', [\n 'name' => 'Events',\n 'args' => [\n 'rest_namespace' => 'wp/v2',\n 'template' => [['core/heading'], ['core/paragraph']],\n 'template_lock' => 'insert',\n ],\n ]);\n});"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/content/taxonomies",
            "title": "Register and use a taxonomy",
            "group": "Content types",
            "description": "A beginner-friendly, complete theme example that registers Project types and displays assigned terms.",
            "sections": [
                {
                    "id": "files",
                    "title": "1. Create the theme files",
                    "text": "This guide keeps registration code separate from the main theme file.\nTEXTCopyyour-theme/\n├── functions.php\n└── inc/\n └── voxycure.php"
                },
                {
                    "id": "load",
                    "title": "2. Load the registration file",
                    "text": "Add this to the active theme’s functions.php. WordPress loads that file automatically on every request.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nrequire_once get_theme_file_path('inc/voxycure.php');"
                },
                {
                    "id": "register",
                    "title": "3. Register Project and Project type",
                    "text": "Paste this entire example into inc/voxycure.php. It creates the post type and connects the taxonomy in one predictable callback.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n // Register the content type before connecting the taxonomy to it.\n $registry->register_post_type('project', [\n 'name' => 'Projects',\n 'singular_name' => 'Project',\n 'show_in_rest' => true,\n 'supports' => ['title', 'editor', 'thumbnail'],\n ]);\n\n $registry->register_taxonomy('project_type', [\n 'name' => 'Project types',\n 'singular_name' => 'Project type',\n 'post_types' => ['project'],\n 'hierarchical' => true,\n 'show_in_rest' => true,\n 'show_admin_column' => true,\n 'rewrite_slug' => 'work/type',\n ]);\n});"
                },
                {
                    "id": "registry-explained",
                    "title": "What $registry means",
                    "text": "The anonymous function is your callback. Voxycure calls it and places its shared Registry object in the callback’s first parameter. That is why $registry exists inside the braces.\nCodeMeaning\nuse Voxyframe\\Core\\Registry;Imports the class name so PHP can type-check the callback parameter.\nadd_action(\"voxycure/register\", ...)Asks WordPress to run your callback when Voxycure is ready.\nRegistry $registryReceives the object supplied by Voxycure. Do not instantiate it yourself.\n$registry->register_taxonomy(...)Adds this taxonomy definition to that registry object."
                },
                {
                    "id": "arguments",
                    "title": "Taxonomy fields explained",
                    "text": "KeyWhat to enterWhat it changes\nproject_typeA stable machine nameThe taxonomy key used by templates and WordPress APIs. Keep it lowercase and no longer than 32 characters.\nnamePlural labelDisplayed as “Project types” in WordPress.\nsingular_nameSingular labelDisplayed when referring to one “Project type”.\npost_typesPost type slugsConnects the taxonomy to project. The post type must also be registered.\nhierarchicaltrue or falsetrue behaves like Categories with parent/child terms; false behaves like Tags.\nshow_in_resttrueMakes terms available to the block editor and REST API.\nshow_admin_columntrueAdds a Project types column to the Projects list.\nrewrite_slugURL baseA term such as “Web” can use /work/type/web/.\nargsNative argument arrayAdds or overrides advanced WordPress register_taxonomy() arguments."
                },
                {
                    "id": "admin-use",
                    "title": "4. Add and assign terms",
                    "text": "Refresh the WordPress dashboard.\nOpen Projects → Project types.\nAdd terms such as Web, Mobile, or Branding.\nEdit a Project, select one or more Project types, and click Update.\nThe relationship is saved by WordPress in its native taxonomy tables. Voxycure does not create a custom table."
                },
                {
                    "id": "render-terms",
                    "title": "5. Display terms in a theme template",
                    "text": "Place this where a Project is being rendered, for example in single-project.php or a template part.\nPHPCopy<?php\n\n$terms = get_the_terms(get_the_ID(), 'project_type');\n\nif ($terms && !is_wp_error($terms)) :\n?>\n <ul class=\"project-types\">\n <?php foreach ($terms as $term) : ?>\n <li>\n <a href=\"<?= esc_url(get_term_link($term)) ?>\">\n <?= esc_html($term->name) ?>\n </a>\n </li>\n <?php endforeach; ?>\n </ul>\n<?php endif; ?>"
                },
                {
                    "id": "permalinks",
                    "title": "6. If the taxonomy URL returns 404",
                    "text": "Open Settings → Permalinks and click Save Changes once after adding or changing a rewrite slug. Do not flush rewrite rules on every request."
                },
                {
                    "id": "official-taxonomy",
                    "title": "Official WordPress references",
                    "text": "register_taxonomy() — native arguments, reserved terms, and slug rules.\nget_the_terms() — retrieve terms assigned to a post.\nadd_action() — understand the callback used by voxycure/register."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/blocks/registering-blocks",
            "title": "Create your first dynamic block",
            "group": "Dynamic blocks",
            "description": "Build a complete Hero block in a theme: registration, fields, secure PHP rendering, CSS, editor use, and saving.",
            "sections": [
                {
                    "id": "result",
                    "title": "What you will build",
                    "text": "The finished Hero block has editable heading, summary, image, button, and alignment fields. WordPress saves those values with the page, while render.php creates the frontend HTML on every render.\nDynamic means rendered by local PHPThe customer’s own WordPress installation runs render.php. No block data is sent to Voxycure. The editor saves attributes instead of final HTML, so updating the template updates every existing Hero block."
                },
                {
                    "id": "structure",
                    "title": "1. Create this folder structure",
                    "text": "TEXTCopyyour-theme/\n├── functions.php\n├── inc/\n│ └── voxycure.php\n└── blocks/\n └── hero/\n ├── render.php\n └── style.cssUse the active theme or child theme. The examples below assume these exact paths."
                },
                {
                    "id": "functions",
                    "title": "2. Load the Voxycure definitions",
                    "text": "Add this once to the theme’s functions.php. get_theme_file_path() returns an absolute, child-theme-aware path.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nrequire_once get_theme_file_path('inc/voxycure.php');"
                },
                {
                    "id": "definition",
                    "title": "3. Register the block and its stylesheet",
                    "text": "Paste this complete file into inc/voxycure.php. The registration callback receives $registry from Voxycure; you do not create the object yourself.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_block('hero', [\n 'label' => 'Hero',\n 'description' => 'Primary page introduction.',\n 'category' => 'design',\n 'icon' => 'cover-image',\n 'keywords' => ['banner', 'header'],\n 'template' => get_theme_file_path('blocks/hero/render.php'),\n 'editor_scope' => ['post_types' => ['page']],\n 'fields' => [\n [\n 'field_key' => 'heading',\n 'label' => 'Heading',\n 'type' => 'text',\n 'default_value' => 'Build something useful',\n ],\n [\n 'field_key' => 'summary',\n 'label' => 'Summary',\n 'type' => 'textarea',\n ],\n [\n 'field_key' => 'image',\n 'label' => 'Image',\n 'type' => 'image',\n ],\n [\n 'field_key' => 'primary_cta',\n 'label' => 'Primary action',\n 'type' => 'link_button',\n ],\n [\n 'field_key' => 'alignment',\n 'label' => 'Text alignment',\n 'type' => 'select',\n 'default_value' => 'left',\n 'location' => 'inspector',\n 'options' => [\n ['value' => 'left', 'label' => 'Left'],\n ['value' => 'center', 'label' => 'Center'],\n ],\n ],\n ],\n ]);\n});\n\nadd_action('after_setup_theme', function (): void {\n wp_enqueue_block_style('voxyframe/hero', [\n 'handle' => 'my-theme-voxycure-hero',\n 'src' => get_theme_file_uri('blocks/hero/style.css'),\n 'path' => get_theme_file_path('blocks/hero/style.css'),\n 'ver' => wp_get_theme()->get('Version'),\n ]);\n});"
                },
                {
                    "id": "definition-fields",
                    "title": "Registration fields explained",
                    "text": "KeyValue in this guidePurpose\nheroStable block IDCreates the WordPress block name voxyframe/hero.\nlabelHeroName developers and editors see in the inserter.\ndescriptionShort explanationHelps editors choose the correct block.\ncategorydesignPlaces it in the Design inserter category.\niconcover-imageUses a WordPress Dashicon slug.\nkeywordsbanner, headerAdditional inserter search terms.\ntemplateAbsolute PHP pathThe trusted PHP file that renders the block.\neditor_scopePagesOffers this Hero only in the block editor for the page post type.\nfieldsField definitionsBuilds editor controls and the block attribute schema.\nlocationinspectorMoves alignment to the editor settings sidebar; other fields remain in the block.\nKeep the ID stableRenaming hero creates a different block. Existing pages would still reference voxyframe/hero."
                },
                {
                    "id": "editor-scope",
                    "title": "Choose where the block appears",
                    "text": "category only groups a block inside the inserter. It does not make a block a page, product, or WooCommerce block. Use editor_scope to control which WordPress editors offer it.\nScope keyMatches\npost_typesPost, page, product, or any public custom post-type slug.\npost_idsExact numeric post or page IDs.\npost_slugsExact post slugs.\ntemplate_slugsA template post such as single-product, when WordPress provides that template post in the editor context.\neditor_contextscore/edit-post, core/edit-site, or another WordPress block-editor context.\nPHPCopy// Every page, but not posts or other custom post types.\n'editor_scope' => [\n 'post_types' => ['page'],\n],\n\n// Only one landing page. Conditions in one rule use AND logic.\n'editor_scope' => [\n 'post_types' => ['page'],\n 'post_ids' => [42],\n],\n\n// Projects OR products. Rules in a list use OR logic.\n'editor_scope' => [\n ['post_types' => ['project']],\n ['post_types' => ['product']],\n],No scope means everywhereOmit editor_scope when a block should be offered in every compatible block editor. Scope changes inserter availability only; already-saved block markup can still render on the frontend.Site Editor limitationWordPress loads some Site Editor settings before a specific template post is selected. Use editor_contexts => ['core/edit-site'] for reliable Site Editor-only visibility. Use template_slugs only when your tested WordPress editor context supplies the template post."
                },
                {
                    "id": "render-file",
                    "title": "4. Create the PHP render file",
                    "text": "Paste this into blocks/hero/render.php. The framework provides $attributes; each array key matches a registered field_key.\nPHPCopy<?php\n/**\n * Hero dynamic block template.\n *\n * Available variables:\n * - $attributes: Saved block field values.\n * - $block_id: Voxycure block ID (\"hero\").\n * - $block_title: Human-readable block label.\n */\n\ndefined('ABSPATH') || exit;\n\n$heading = (string) ($attributes['heading'] ?? '');\n$summary = (string) ($attributes['summary'] ?? '');\n$image = (array) ($attributes['image'] ?? []);\n$link = (array) ($attributes['primary_cta'] ?? []);\n$alignment = (string) ($attributes['alignment'] ?? 'left');\n\nif (!in_array($alignment, ['left', 'center'], true)) {\n $alignment = 'left';\n}\n?>\n<section <?= get_block_wrapper_attributes([\n 'class' => 'vc-hero vc-hero--' . $alignment,\n]) ?>>\n <div class=\"vc-hero__content\">\n <?php if ($heading !== '') : ?>\n <h2 class=\"vc-hero__heading\"><?= esc_html($heading) ?></h2>\n <?php endif; ?>\n\n <?php if ($summary !== '') : ?>\n <p class=\"vc-hero__summary\"><?= esc_html($summary) ?></p>\n <?php endif; ?>\n\n <?php if (!empty($link['url']) && !empty($link['text'])) : ?>\n <a class=\"vc-hero__button\" href=\"<?= esc_url($link['url']) ?>\">\n <?= esc_html($link['text']) ?>\n </a>\n <?php endif; ?>\n </div>\n\n <?php if (!empty($image['id'])) : ?>\n <div class=\"vc-hero__media\">\n <?= wp_get_attachment_image((int) $image['id'], 'large') ?>\n </div>\n <?php endif; ?>\n</section>"
                },
                {
                    "id": "security",
                    "title": "Why the render code is safe",
                    "text": "esc_html() escapes visible text.\nesc_url() escapes the link destination.\nwp_get_attachment_image() renders responsive WordPress image markup from a trusted attachment ID.\nThe alignment is checked against an allow-list before becoming a CSS class.\nget_block_wrapper_attributes() preserves WordPress-generated block classes and attributes.\nWordPress output escaping guide · wp_get_attachment_image()"
                },
                {
                    "id": "style-file",
                    "title": "5. Add the block styles",
                    "text": "Paste this into blocks/hero/style.css. The earlier wp_enqueue_block_style() call makes it available in both the editor and frontend; themes that load block assets on demand can load it only when the Hero is rendered.\nCSSCopy.vc-hero {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(18rem, .8fr);\n gap: clamp(2rem, 6vw, 6rem);\n align-items: center;\n padding-block: clamp(3rem, 8vw, 7rem);\n}\n\n.vc-hero--center .vc-hero__content {\n text-align: center;\n}\n\n.vc-hero__heading {\n margin: 0;\n font-size: clamp(2.5rem, 6vw, 5.5rem);\n line-height: 1;\n}\n\n.vc-hero__summary {\n max-width: 42rem;\n font-size: 1.125rem;\n}\n\n.vc-hero__button {\n display: inline-flex;\n padding: .8rem 1.2rem;\n border-radius: .4rem;\n color: #fff;\n background: #1d49c3;\n text-decoration: none;\n}\n\n.vc-hero__media img {\n display: block;\n width: 100%;\n height: auto;\n border-radius: 1rem;\n}\n\n@media (max-width: 700px) {\n .vc-hero {\n grid-template-columns: 1fr;\n }\n}WordPress: wp_enqueue_block_style()"
                },
                {
                    "id": "editor",
                    "title": "6. Insert and save the block",
                    "text": "Open Pages → Add New or edit an existing page.\nClick the + block inserter and search for Hero, banner, or header.\nEnter the heading and summary, choose an image, and fill in the button.\nOpen the block settings sidebar to choose text alignment.\nClick Publish or Update, then view the page."
                },
                {
                    "id": "saving",
                    "title": "How the values are saved",
                    "text": "Each field becomes a typed block attribute. The Voxycure editor calls WordPress setAttributes(); WordPress serializes the attributes into the block comment inside post_content. Autosaves, revisions, undo, and the normal page update flow continue to work. Voxycure does not submit a second request or store the values in a custom table."
                },
                {
                    "id": "changes",
                    "title": "Change an existing block later",
                    "text": "Markup change: edit render.php; all existing Hero blocks use it immediately.\nDesign change: edit style.css.\nNew field: add its definition and read the new key with a fallback in render.php.\nRemoved field: stop rendering it first. Old saved attributes may remain harmlessly in page content."
                },
                {
                    "id": "troubleshoot",
                    "title": "If the block does not appear",
                    "text": "Confirm Voxycure Framework is installed and active.\nConfirm functions.php loads inc/voxycure.php.\nDo not place the registration inside init; use voxycure/register.\nConfirm blocks/hero/render.php exists and the filename case matches.\nOpen the browser console and WordPress debug log for PHP or JavaScript errors."
                },
                {
                    "id": "official-dynamic",
                    "title": "Official WordPress references",
                    "text": "Creating dynamic blocks — how blocks are rendered by PHP in WordPress.\nRegistration of a block — current native registration guidance.\nget_theme_file_path() — resolve theme files safely."
                },
                {
                    "id": "native-blocks",
                    "title": "When to use block.json instead",
                    "text": "Voxycure is well suited to PHP-rendered theme sections with shared fields. Use a native block.json build when a block needs custom editor JavaScript, variations, bindings, advanced supports, or the Interactivity API."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/blocks/templates",
            "title": "PHP block templates",
            "group": "Dynamic blocks",
            "description": "Render attributes safely while keeping markup in your theme.",
            "sections": [
                {
                    "id": "contract",
                    "title": "Template contract",
                    "text": "The template runs inside the render callback and receives $attributes. It must be a PHP file below WP_CONTENT_DIR or another explicitly trusted root.\nPHPCopy<?php\n$heading = (string) ($attributes['heading'] ?? '');\n$image = (array) ($attributes['image'] ?? []);\n?>\n<section <?= get_block_wrapper_attributes(['class' => 'hero']) ?>>\n <h2><?= esc_html($heading) ?></h2>\n <?= wp_get_attachment_image((int) ($image['id'] ?? 0), 'full') ?>\n</section>"
                },
                {
                    "id": "escaping",
                    "title": "Escape for the output context",
                    "text": "ContextFunction\nVisible textesc_html()\nHTML attributeesc_attr()\nURLesc_url()\nTrusted rich HTMLwp_kses_post()\nAttachment imagewp_get_attachment_image()"
                },
                {
                    "id": "roots",
                    "title": "Additional trusted roots",
                    "text": "PHPCopyadd_filter('voxycure_template_roots', function (array $roots): array {\n $roots[] = '/srv/shared-wordpress-templates';\n return $roots;\n});Security boundaryOnly add directories controlled by trusted developers. Never add an uploads directory."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/blocks/attributes",
            "title": "Attributes and persistence",
            "group": "Dynamic blocks",
            "description": "Block field values are serialized by WordPress into the block comment stored in post content.",
            "sections": [
                {
                    "id": "mapping",
                    "title": "Field-to-attribute mapping",
                    "text": "FieldBlock attribute type\nText, textarea, select, radio, date, colorstring\nNumber, range slidernumber\nToggle, single checkboxboolean\nMulti-select, gallery, repeaterarray\nImage, link buttonobject"
                },
                {
                    "id": "save",
                    "title": "How saving works",
                    "text": "The shared editor calls setAttributes(). WordPress includes the new attributes in the normal post save, undo history, autosaves, and revisions. Voxycure does not create a second save request."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/blocks/caching",
            "title": "Block output caching",
            "group": "Dynamic blocks",
            "description": "Opt in to WordPress object-cache storage for expensive, context-stable dynamic output.",
            "sections": [
                {
                    "id": "enable",
                    "title": "Enable per block",
                    "text": "Register this from the theme file loaded by functions.php. A TTL of 300 caches matching output for five minutes.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_block('project-grid', [\n 'label' => 'Project grid',\n 'template' => get_theme_file_path('blocks/project-grid.php'),\n 'cache_ttl' => 300,\n 'fields' => [],\n ]);\n});"
                },
                {
                    "id": "key",
                    "title": "Cache key inputs",
                    "text": "The cache key contains the block ID, serialized attributes, current post ID, and locale. A persistent object-cache plugin is required for values to survive between PHP requests."
                },
                {
                    "id": "filter",
                    "title": "Central cache policy",
                    "text": "PHPCopyadd_filter('voxycure_block_cache_ttl', function (int $ttl, string $blockId): int {\n return 'project-grid' === $blockId ? HOUR_IN_SECONDS : $ttl;\n}, 10, 2);Avoid personalized outputDo not cache blocks containing user-specific, nonce, cart, session, or capability-dependent markup."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/overview",
            "title": "Field reference",
            "group": "Field reference",
            "description": "Every field uses a consistent definition shape and is sanitized according to its saved value type.",
            "sections": [
                {
                    "id": "anatomy",
                    "title": "Field anatomy",
                    "text": "PHPCopy[\n 'field_key' => 'heading',\n 'label' => 'Heading',\n 'type' => 'text',\n 'default_value' => '',\n 'required' => true,\n 'location' => 'default',\n]Storage keyUse a stable, unique field_key. Changing it after content exists starts reading and writing a new value."
                },
                {
                    "id": "types",
                    "title": "Available field types",
                    "text": "Choose a field below for its value shape, complete definition, sanitization behavior, and rendering example.\nTexttextTextareatextareaNumbernumberRange sliderrange_sliderToggletoggleCheckboxcheckboxRadioradioSelectselectMulti selectmulti_selectDatedateColorcolorImageimageGallerygalleryLink buttonlink_buttonRepeaterrepeater"
                },
                {
                    "id": "conditional",
                    "title": "Conditional logic",
                    "text": "PHPCopy'conditional_logic' => [\n ['field' => 'show_cta', 'operator' => '==', 'value' => true],\n]Conditional logic changes editor visibility. It is not a security control and does not remove an already-saved value."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/groups",
            "title": "Document field groups",
            "group": "Field reference",
            "description": "Attach registered fields to posts, pages, products, or your own REST-enabled post types.",
            "sections": [
                {
                    "id": "example",
                    "title": "Register a group",
                    "text": "Paste this complete example into the registration file loaded by your theme.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_field_group('page-details', [\n 'name' => 'Page details',\n 'post_types' => ['page'],\n 'fields' => [\n ['field_key' => 'kicker', 'label' => 'Kicker', 'type' => 'text'],\n ['field_key' => 'featured', 'label' => 'Featured', 'type' => 'toggle'],\n ],\n ]);\n});"
                },
                {
                    "id": "persistence",
                    "title": "Persistence and permissions",
                    "text": "Voxycure registers each key with register_post_meta(), adds custom-fields support when needed, and authorizes writes with current_user_can(\"edit_post\", $post_id). Complex types receive explicit REST schemas."
                },
                {
                    "id": "read",
                    "title": "Read a field",
                    "text": "PHPCopy$value = voxycure_get_field('kicker');\n$otherPostValue = voxycure_get_field('kicker', 42, 'Fallback');"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/options/registering-pages",
            "title": "Option pages",
            "group": "Options",
            "description": "Create settings screens from PHP while saving only explicitly registered and sanitized fields.",
            "sections": [
                {
                    "id": "example",
                    "title": "Complete page",
                    "text": "Paste this complete example into the registration file loaded by your theme.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_option_page('theme-settings', [\n 'name' => 'Theme settings',\n 'page_title' => 'Theme settings',\n 'option_key' => 'theme_settings',\n 'capability' => 'manage_options',\n 'icon' => 'dashicons-admin-customizer',\n 'position' => 58,\n 'autoload' => false,\n 'fields' => [\n ['field_key' => 'brand_color', 'label' => 'Brand color', 'type' => 'color'],\n ['field_key' => 'support_email', 'label' => 'Support email', 'type' => 'text'],\n ],\n ]);\n});"
                },
                {
                    "id": "security",
                    "title": "Save security",
                    "text": "The REST route rejects unregistered option keys, checks the page capability, ignores unregistered fields, validates required values, sanitizes by field type, and then calls update_option()."
                },
                {
                    "id": "read",
                    "title": "Read an option",
                    "text": "PHPCopy$color = voxycure_get_option('theme_settings.brand_color', '#1d49c3');"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/options/tabs",
            "title": "Tabbed option pages",
            "group": "Options",
            "description": "Group larger settings screens into predictable nested arrays.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Define tabs and assignments",
                    "text": "PHPCopy'tabs' => [\n ['value' => 'branding', 'label' => 'Branding'],\n ['value' => 'social', 'label' => 'Social profiles'],\n],\n'fields' => [\n ['field_key' => 'logo_text', 'label' => 'Logo text', 'type' => 'text', 'tab' => 'branding'],\n ['field_key' => 'linkedin', 'label' => 'LinkedIn URL', 'type' => 'text', 'tab' => 'social'],\n],"
                },
                {
                    "id": "shape",
                    "title": "Saved option shape",
                    "text": "PHPCopy[\n 'branding' => ['logo_text' => 'Voxycure'],\n 'social' => ['linkedin' => 'https://linkedin.com/company/example'],\n]"
                },
                {
                    "id": "read",
                    "title": "Read a nested value",
                    "text": "PHPCopy$linkedin = voxycure_get_option('theme_settings.social.linkedin');"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/api/helpers",
            "title": "Template helpers",
            "group": "API reference",
            "description": "Read native WordPress values with defaults and nested option paths.",
            "sections": [
                {
                    "id": "field",
                    "title": "voxycure_get_field()",
                    "text": "PHPCopyvoxycure_get_field(string $key, ?int $postId = null, mixed $default = null): mixedArgumentMeaning\n$keyRegistered meta key.\n$postIdDefaults to get_the_ID().\n$defaultReturned when no post/value exists."
                },
                {
                    "id": "option",
                    "title": "voxycure_get_option()",
                    "text": "PHPCopyvoxycure_get_option(string $key, mixed $default = null): mixedDot notation traverses nested arrays and objects, for example theme_settings.branding.logo."
                },
                {
                    "id": "registry",
                    "title": "voxycure_registry()",
                    "text": "Returns the shared Voxyframe\\Core\\Registry. Prefer the registration action so other extensions can predict the load order."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/api/hooks",
            "title": "Hooks and filters",
            "group": "API reference",
            "description": "Adjust definitions, native registration arguments, caching policy, and save behavior.",
            "sections": [
                {
                    "id": "registration",
                    "title": "Registration hooks",
                    "text": "HookTypePurpose\nvoxycure/registerActionPrimary definition entry point.\nvoxycure_register_post_typesFilterFilter collected post-type definitions.\nvoxycure_register_taxonomiesFilterFilter taxonomy definitions.\nvoxycure_blocksFilterFilter dynamic blocks.\nvoxycure_meta_fieldsFilterFilter document field groups.\nvoxycure_option_pagesFilterFilter option pages."
                },
                {
                    "id": "runtime",
                    "title": "Runtime hooks",
                    "text": "HookPurpose\nvoxycure_post_type_argsModify final native post-type arguments.\nvoxycure_taxonomy_argsModify final native taxonomy arguments.\nvoxycure_block_cache_ttlSet output cache lifetime.\nvoxycure_block_editor_scope_matchOverride the final inserter-visibility decision for one Voxycure block and editor context.\nvoxycure_template_rootsAdd a trusted PHP-template root.\nvoxycure_options_savedRun after a registered option page saves."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/api/security",
            "title": "Security model",
            "group": "API reference",
            "description": "Understand the trust boundaries and the responsibilities that remain in theme templates.",
            "sections": [
                {
                    "id": "input",
                    "title": "Input protection",
                    "text": "Option writes are allow-listed by page and field.\nPost meta uses type-specific sanitizers and REST schemas.\nPost writes require permission for the exact post.\nOption pages require their configured capability.\nTemplate paths must resolve to approved PHP files."
                },
                {
                    "id": "output",
                    "title": "Output escaping is your responsibility",
                    "text": "Sanitizing stored data does not replace context-aware output escaping. Escape at the last possible moment in PHP templates.\nPHPCopy<a href=\"<?= esc_url($url) ?>\" data-label=\"<?= esc_attr($label) ?>\">\n <?= esc_html($label) ?>\n</a>"
                },
                {
                    "id": "cache",
                    "title": "Caching security",
                    "text": "Cached HTML can cross user requests when persistent object caching is enabled. Never cache output containing nonces, private data, account state, or cart/session content."
                },
                {
                    "id": "privacy",
                    "title": "Privacy and outbound requests",
                    "text": "Voxycure Framework contains no telemetry client and sends no activation, deactivation, update, usage, site URL, content, field, block, or option data to Voxycure. Plugin activation only creates a short-lived local transient so WordPress can refresh rewrite rules once.\nLocal WordPress processing“PHP-rendered” and “registered with WordPress using PHP” refer to code running on the customer’s own hosting server. They do not mean the Voxycure website or a remote API."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/integrations/wordpress",
            "title": "Modern WordPress development",
            "group": "Integrations",
            "description": "Use Voxycure for concise theme features while following current WordPress block and REST conventions.",
            "sections": [
                {
                    "id": "blocks",
                    "title": "Block registration direction",
                    "text": "Voxycure registers dynamic blocks with WordPress using PHP and Block API version 3. All registration and rendering happen inside the customer’s WordPress installation; Voxycure does not receive block definitions or saved values. For independent blocks with scripts, styles, variations, bindings, or interactive directives, use block.json. WordPress 6.8+ recommends metadata collections for registering many metadata-based blocks.\nWordPress block registration guide"
                },
                {
                    "id": "meta",
                    "title": "REST meta requirements",
                    "text": "REST-visible array meta must declare an item schema, and the post type must support custom-fields. Voxycure handles both when registering field groups.\nWordPress REST response guide"
                },
                {
                    "id": "native",
                    "title": "Prefer native APIs",
                    "text": "Use WordPress template, escaping, media, capability, translation, and cache functions inside framework callbacks. Voxycure does not replace those APIs."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/integrations/woocommerce-product-editor",
            "title": "WooCommerce Product Editor and product blocks",
            "group": "Integrations",
            "description": "Understand the Product Editor v3 status, add supported product fields, and build a dynamic block for the Single Product template.",
            "sections": [
                {
                    "id": "status",
                    "title": "Product Editor v3 status",
                    "text": "No stable v3 extension APIAs of August 2026, theme and extension developers cannot register blocks inside a released WooCommerce Product Editor v3. WooCommerce retired the previous block-based Product Editor beta in WooCommerce 11.0. The proposed v3 direction uses WordPress DataForms and DataViews, but WooCommerce has not published a stable production API for adding v3 editor blocks.Do not use @woocommerce/product-editor, product-block-editor-v1, @woocommerce/create-product-editor-block, or editor APIs marked __experimental. Those belong to the retired beta and are not a future-safe Voxycure integration."
                },
                {
                    "id": "surfaces",
                    "title": "Do not confuse these three editor surfaces",
                    "text": "SurfaceWhat developers customizeCurrent approach\nWooCommerce Admin product editorThe form merchants use to edit price, stock, shipping, and custom product data.Use the supported classic product editor hooks and WooCommerce CRUD today. Product Editor v3 has no stable public block API.\nSingle Product template editorThe storefront layout shoppers see for one product.Build product-display blocks and insert them into the WooCommerce Single Product template in the Site Editor.\nProduct Collection and catalog blocksProduct grids, catalog queries, filters, Cart, and Checkout.Use the documented WooCommerce Blocks extension surfaces for that specific block."
                },
                {
                    "id": "version-matrix",
                    "title": "WooCommerce version matrix",
                    "text": "WooCommerceProduct editor stateWhat your code should do\n10.8 and earlierOld block-based editor beta may exist behind a feature flag.Do not begin new integrations with its experimental APIs.\n10.9Deprecation window and warnings.Remove beta-only imports, blocks, slots, and feature declarations.\n11.0 and newerOld beta editor and @woocommerce/product-editor are removed.Use the Voxycure editor => woocommerce adapter, which wraps the stable classic editor and product CRUD."
                },
                {
                    "id": "ownership",
                    "title": "Theme or companion plugin?",
                    "text": "The examples below can live in a theme because this guide targets theme developers. Product data usually belongs in a small companion plugin, however, so merchants can still edit the field after changing themes. The frontend display block and CSS naturally belong in the theme."
                },
                {
                    "id": "files",
                    "title": "1. Create the files",
                    "text": "TEXTCopyyour-theme/\n├── functions.php\n├── inc/\n│ ├── voxycure.php\n│ └── blocks.php\n└── blocks/\n └── product-delivery-note/\n ├── render.php\n └── style.css"
                },
                {
                    "id": "load",
                    "title": "2. Load the integration from functions.php",
                    "text": "WordPress loads the active theme’s functions.php. Load the child-theme-aware registration files; developers do not add WooCommerce rendering or save hooks themselves.\nPHPCopy<?php\n\ndefined('ABSPATH') || exit;\n\nrequire_once get_theme_file_path('inc/voxycure.php');\nrequire_once get_theme_file_path('inc/blocks.php');"
                },
                {
                    "id": "product-field",
                    "title": "3. Register the product field with Voxycure",
                    "text": "Paste this into inc/voxycure.php. Voxycure detects the product post type and editor => woocommerce, renders the field in Product data → Inventory, verifies WooCommerce’s save nonce, sanitizes the submitted value by field type, checks the product-edit capability, and updates the same WC_Product object that WooCommerce saves.\nPHPCopy<?php\n/**\n * Register a product field through Voxycure Framework.\n * File: inc/voxycure.php\n */\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n $registry->register_field_group('product-delivery', [\n 'name' => 'Delivery details',\n 'post_types' => ['product'],\n 'editor' => 'woocommerce',\n 'woocommerce_tab' => 'inventory',\n 'fields' => [\n [\n 'field_key' => '_vc_delivery_note',\n 'label' => 'Delivery note',\n 'type' => 'text',\n 'description' => 'Shown on the product page, for example “Usually ships in 2 days”.',\n 'desc_tip' => true,\n 'placeholder' => 'Usually ships in 2 business days',\n ],\n ],\n ]);\n});KeyPurpose\npost_types => ['product']Connects the field group to WooCommerce products.\neditor => 'woocommerce'Uses the Voxycure WooCommerce adapter instead of the WordPress document settings panel.\nwoocommerce_tabChoose general, inventory, shipping, linked, or advanced.\nfield_keyThe stable product-meta key read through WC_Product::get_meta().\nNo manual WooCommerce hooksDo not call woocommerce_wp_text_input(), read $_POST, or call save_meta_data() in the theme. Voxycure owns that adapter and WooCommerce performs the final product save.Stable developer definitionKeep this registry definition in project code. If WooCommerce publishes a future stable Product Editor v3 extension API, Voxycure can update its internal adapter without forcing theme developers to rewrite the field definition.Supported product controlsThe stable adapter supports text, textarea, number, range, date, color, URL, select, radio, checkbox, and toggle controls. Complex media, gallery, repeater, and multi-select product controls are not silently downgraded; use a purpose-built WooCommerce extension UI for those until Voxycure documents support."
                },
                {
                    "id": "test-field",
                    "title": "4. Test product saving",
                    "text": "Open Products → Add New or edit a product.\nOpen Product data → Inventory.\nEnter a value such as Usually ships in 2 business days.\nClick Publish or Update.\nReload the product and confirm the value remains."
                },
                {
                    "id": "register-block",
                    "title": "5. Register a storefront product block",
                    "text": "This is a Voxycure dynamic block for the storefront Site Editor—not an admin Product Editor v3 block. Paste it into inc/blocks.php. The woocommerce category only controls inserter grouping. Its editor_scope prevents the block from appearing in normal post, page, or product post editors.\nPHPCopy<?php\n/**\n * Register the frontend product delivery-note block.\n * File: inc/blocks.php\n */\n\ndefined('ABSPATH') || exit;\n\nuse Voxyframe\\Core\\Registry;\n\nadd_action('voxycure/register', function (Registry $registry): void {\n if (!class_exists('WooCommerce')) {\n return;\n }\n\n $registry->register_block('product-delivery-note', [\n 'label' => 'Product delivery note',\n 'description' => 'Displays the delivery note saved on the current WooCommerce product.',\n 'category' => 'woocommerce',\n 'icon' => 'car',\n 'keywords' => ['product', 'delivery', 'shipping'],\n 'template' => get_theme_file_path('blocks/product-delivery-note/render.php'),\n 'editor_scope' => ['editor_contexts' => ['core/edit-site']],\n 'fields' => [],\n 'cache_ttl' => 0,\n ]);\n});\n\nadd_action('after_setup_theme', function (): void {\n wp_enqueue_block_style('voxyframe/product-delivery-note', [\n 'handle' => 'my-theme-product-delivery-note',\n 'src' => get_theme_file_uri('blocks/product-delivery-note/style.css'),\n 'path' => get_theme_file_path('blocks/product-delivery-note/style.css'),\n 'ver' => wp_get_theme()->get('Version'),\n ]);\n});Why core/edit-site?Current WordPress Site Editor settings are shared and may be created before a specific template post is selected. Targeting core/edit-site is reliable; the block render template still exits safely unless the frontend has a valid WooCommerce product context.Caching is intentionally offProduct data can change independently of template content. Keep cache_ttl at 0 unless your project also invalidates the cached block whenever this product meta changes."
                },
                {
                    "id": "render-block",
                    "title": "6. Render the current product value",
                    "text": "Paste this into blocks/product-delivery-note/render.php. It exits safely outside a valid product context and escapes the saved value at output.\nPHPCopy<?php\n/**\n * Render the delivery note for the product currently being displayed.\n * File: blocks/product-delivery-note/render.php\n */\n\ndefined('ABSPATH') || exit;\n\nif (!function_exists('wc_get_product')) {\n return;\n}\n\n$product = wc_get_product(get_the_ID());\nif (!$product instanceof WC_Product) {\n return;\n}\n\n$deliveryNote = (string) $product->get_meta('_vc_delivery_note', true);\nif ($deliveryNote === '') {\n return;\n}\n?>\n<div <?= get_block_wrapper_attributes(['class' => 'vc-product-delivery-note']) ?>>\n <strong><?= esc_html__('Delivery', 'my-theme') ?></strong>\n <span><?= esc_html($deliveryNote) ?></span>\n</div>"
                },
                {
                    "id": "style-block",
                    "title": "7. Add the block style",
                    "text": "Paste this into blocks/product-delivery-note/style.css. WordPress can load it with the block in the editor and frontend.\nCSSCopy.vc-product-delivery-note {\n display: flex;\n gap: .6rem;\n align-items: baseline;\n padding: 1rem 1.1rem;\n border: 1px solid currentColor;\n border-radius: .5rem;\n}\n\n.vc-product-delivery-note strong {\n font-weight: 600;\n}"
                },
                {
                    "id": "insert-block",
                    "title": "8. Add it to the Single Product template",
                    "text": "Open Appearance → Editor.\nOpen Design → Templates, then choose the WooCommerce Single Product template. Menu wording can differ slightly by WordPress version.\nInsert Product delivery note where it should appear, such as below Product Price or Add to Cart.\nSave the template and visit a product that has a delivery note.\nThe block may render empty when the editor has no preview product. On a real single-product request, it reads the current product through WooCommerce."
                },
                {
                    "id": "not-v3",
                    "title": "What to do when Product Editor v3 ships",
                    "text": "Wait for WooCommerce to publish a stable public extension API and migration guide. At that point, keep the existing WC_Product data key and replace only the admin field UI. The storefront block can continue reading _vc_delivery_note through WooCommerce CRUD.\nDo not guess the APIDataForms, DataViews, and custom field types describe WooCommerce’s direction, not a production contract. Do not ship code copied from internal namespaces or proof-of-concept branches."
                },
                {
                    "id": "official-product-editor",
                    "title": "Official WooCommerce references",
                    "text": "Product editor beta retirement in WooCommerce 11.0\nProduct Editor v3 direction and DataForms plan\nAdding custom product fields with WooCommerce CRUD\nTheming WooCommerce blocks and templates\nWooCommerce block reference"
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/integrations/woocommerce",
            "title": "WooCommerce",
            "group": "Integrations",
            "description": "Keep commerce extensions HPOS-safe and use the supported Blocks extension surfaces.",
            "sections": [
                {
                    "id": "crud",
                    "title": "Products and orders",
                    "text": "Use WooCommerce CRUD objects rather than querying order posts, post meta, or custom tables.\nPHPCopy$product = wc_get_product($productId);\n$sku = $product ? $product->get_sku() : '';\n\n$order = wc_get_order($orderId);\n$order->update_meta_data('dispatch_note', sanitize_text_field($note));\n$order->save();"
                },
                {
                    "id": "hpos",
                    "title": "High-Performance Order Storage",
                    "text": "HPOS can store orders outside wp_posts. WooCommerce CRUD methods abstract the active datastore. Declare compatibility only after testing your complete extension.\nWooCommerce HPOS recipe book"
                },
                {
                    "id": "blocks",
                    "title": "Cart and Checkout blocks",
                    "text": "Use the Store API, documented filters, Slot/Fills, inner blocks, or IntegrationInterface. Classic shortcode hooks do not all run in block-based Cart and Checkout.\nWooCommerce Blocks extensibility"
                },
                {
                    "id": "product-editor",
                    "title": "Product editor",
                    "text": "WooCommerce 11.0 removed the old block-based Product Editor beta. Product Editor v3 does not currently expose a stable public block API. Read the complete Product Editor and product blocks guide for the supported product-field workflow and a Single Product template block."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/help/troubleshooting",
            "title": "Troubleshooting",
            "group": "Help",
            "description": "Common registration, editor, persistence, template, and caching problems.",
            "sections": [
                {
                    "id": "missing",
                    "title": "Definition does not appear",
                    "text": "Confirm the plugin is active.\nRegister on voxycure/register, not after init.\nUse a unique sanitized slug or block ID.\nEnsure the target post type exists and show_in_rest is enabled."
                },
                {
                    "id": "saving",
                    "title": "Field does not save",
                    "text": "Confirm field_key is present and stable.\nCheck the browser REST response for schema errors.\nVerify the current user can edit that post or manage that option page.\nFor option tabs, ensure the field tab matches a tab value."
                },
                {
                    "id": "template",
                    "title": "Block template warning",
                    "text": "Use an absolute path such as get_theme_file_path().\nThe file must exist, end in .php, and be under an approved root.\nDo not pass a public URL as the template path."
                },
                {
                    "id": "rewrite",
                    "title": "New URLs return 404",
                    "text": "Deactivate and reactivate the plugin once, or visit Settings → Permalinks. Never flush rewrite rules on every request."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/text",
            "title": "Text field",
            "group": "Field reference",
            "description": "A single-line value for titles, labels, IDs, and short content.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'eyebrow', 'label' => 'Eyebrow', 'type' => 'text', 'default_value' => 'Featured']"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typetext\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationSanitized with sanitize_text_field(). HTML is removed."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['eyebrow'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/textarea",
            "title": "Textarea field",
            "group": "Field reference",
            "description": "Multi-line plain text such as summaries, notes, or addresses.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'summary', 'label' => 'Summary', 'type' => 'textarea', 'required' => true]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typetextarea\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationSanitized with sanitize_textarea_field(). Use a block or rich-text implementation when formatting is required."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['summary'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/number",
            "title": "Number field",
            "group": "Field reference",
            "description": "A numeric value stored through the REST API as a number.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'items_per_row', 'label' => 'Items per row', 'type' => 'number', 'default_value' => 3]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typenumber\nPHP / REST valuenumber\nEmpty value\"\" or the configured default\nSanitizationNon-numeric input becomes 0. Validate business limits in your rendering or save hook."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['items_per_row'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/range-slider",
            "title": "Range slider field",
            "group": "Field reference",
            "description": "A visual numeric range control with an optional minimum, maximum, and step.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'overlay', 'label' => 'Overlay', 'type' => 'range_slider', 'default_value' => 40, 'range_config' => ['min' => 0, 'max' => 100, 'step' => 5]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typerange_slider\nPHP / REST valuenumber\nEmpty value\"\" or the configured default\nSanitizationStored as a number. Keep the default inside the configured range."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['overlay'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/toggle",
            "title": "Toggle field",
            "group": "Field reference",
            "description": "A true/false switch for feature flags and display decisions.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'show_cta', 'label' => 'Show call to action', 'type' => 'toggle', 'default_value' => true]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typetoggle\nPHP / REST valueboolean\nEmpty value\"\" or the configured default\nSanitizationValues are normalized with rest_sanitize_boolean()."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopyif (!empty($attributes['show_cta'])) {\n echo '<a class=\"button\" href=\"/contact/\">Contact us</a>';\n}"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/checkbox",
            "title": "Checkbox field",
            "group": "Field reference",
            "description": "A single checkbox stores a boolean. Supplying options turns it into a multiple-choice checkbox group.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'features', 'label' => 'Features', 'type' => 'checkbox', 'options' => [['value' => 'fast', 'label' => 'Fast'], ['value' => 'secure', 'label' => 'Secure']]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typecheckbox\nPHP / REST valueboolean or string[]\nEmpty value\"\" or the configured default\nSanitizationAn option group is stored as a sequential array of sanitized strings."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['features'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/radio",
            "title": "Radio field",
            "group": "Field reference",
            "description": "A single value selected from a short, visible list of choices.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'alignment', 'label' => 'Alignment', 'type' => 'radio', 'default_value' => 'left', 'options' => [['value' => 'left', 'label' => 'Left'], ['value' => 'center', 'label' => 'Center']]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typeradio\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationUse select when the option list is long."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['alignment'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/select",
            "title": "Select field",
            "group": "Field reference",
            "description": "A compact single-choice dropdown.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'heading_level', 'label' => 'Heading level', 'type' => 'select', 'default_value' => 'h2', 'options' => [['value' => 'h2', 'label' => 'H2'], ['value' => 'h3', 'label' => 'H3']]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typeselect\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationAlways escape the selected value before using it in HTML attributes."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['heading_level'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/multi-select",
            "title": "Multi select field",
            "group": "Field reference",
            "description": "A token-based control for choosing more than one value.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'audiences', 'label' => 'Audiences', 'type' => 'multi_select', 'options' => [['value' => 'agency', 'label' => 'Agency'], ['value' => 'startup', 'label' => 'Startup']]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typemulti_select\nPHP / REST valuestring[]\nEmpty value[]\nSanitizationStored as a sequential string array with an explicit REST item schema."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['audiences'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/date",
            "title": "Date field",
            "group": "Field reference",
            "description": "A calendar date value for events, deadlines, or publishing context.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'launch_date', 'label' => 'Launch date', 'type' => 'date']"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typedate\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationTreat the saved value as a date string. Convert with WordPress date helpers before presentation."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['launch_date'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/color",
            "title": "Color field",
            "group": "Field reference",
            "description": "A color picker that stores a CSS color value.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'accent_color', 'label' => 'Accent color', 'type' => 'color', 'default_value' => '#1d49c3']"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typecolor\nPHP / REST valuestring\nEmpty value\"\" or the configured default\nSanitizationEscape for the destination context. Use esc_attr() inside a style attribute."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$value = $attributes['accent_color'] ?? '';\necho esc_html(is_array($value) ? implode(', ', $value) : (string) $value);"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/image",
            "title": "Image field",
            "group": "Field reference",
            "description": "A Media Library selection stored as an object containing an attachment ID and URL.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'portrait', 'label' => 'Portrait', 'type' => 'image']"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typeimage\nPHP / REST valueobject\nEmpty value\"\" or the configured default\nSanitizationPrefer the attachment id with wp_get_attachment_image(); the stored URL is convenient but less adaptable."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$image = $attributes['portrait'] ?? [];\necho wp_get_attachment_image((int) ($image['id'] ?? 0), 'large');"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/gallery",
            "title": "Gallery field",
            "group": "Field reference",
            "description": "An ordered list of Media Library images.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'gallery', 'label' => 'Gallery', 'type' => 'gallery']"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typegallery\nPHP / REST valueobject[]\nEmpty value[]\nSanitizationEach item has an integer id and sanitized url. The REST schema validates every item."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopyforeach ((array) ($attributes['gallery'] ?? []) as $image) {\n echo wp_get_attachment_image((int) $image['id'], 'large');\n}"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/link-button",
            "title": "Link button field",
            "group": "Field reference",
            "description": "A paired button label and destination URL.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'primary_cta', 'label' => 'Primary action', 'type' => 'link_button', 'default_value' => ['text' => 'Learn more', 'url' => '/about/']]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typelink_button\nPHP / REST valueobject\nEmpty value\"\" or the configured default\nSanitizationThe URL is sanitized with esc_url_raw() when saved. Escape it again with esc_url() when rendered."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopy$link = $attributes['primary_cta'] ?? [];\nprintf('<a href=\"%s\">%s</a>', esc_url($link['url'] ?? ''), esc_html($link['text'] ?? ''));"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        },
        {
            "url": "https://framework.voxycureinfotech.com/fields/repeater",
            "title": "Repeater field",
            "group": "Field reference",
            "description": "A repeatable list of rows with a defined child-field schema.",
            "sections": [
                {
                    "id": "definition",
                    "title": "Field definition",
                    "text": "Add this array inside a block, field group, or option page fields list.\nPHPCopy['field_key' => 'stats', 'label' => 'Statistics', 'type' => 'repeater', 'fields' => [['field_key' => 'value', 'label' => 'Value', 'type' => 'text'], ['field_key' => 'label', 'label' => 'Label', 'type' => 'text']]]"
                },
                {
                    "id": "value",
                    "title": "Saved value",
                    "text": "PropertyValue\nField typerepeater\nPHP / REST valueobject[]\nEmpty value[]\nSanitizationChild keys become the REST object properties. Define every child explicitly so invalid properties are rejected."
                },
                {
                    "id": "rendering",
                    "title": "Rendering example",
                    "text": "Read block fields from $attributes. Post fields use voxycure_get_field(); option fields use voxycure_get_option().\nPHPCopyforeach ((array) ($attributes['stats'] ?? []) as $row) {\n printf('<strong>%s</strong><span>%s</span>', esc_html($row['value'] ?? ''), esc_html($row['label'] ?? ''));\n}"
                },
                {
                    "id": "common-options",
                    "title": "Common field options",
                    "text": "KeyTypePurpose\nfield_keystringRequired unique storage key using lowercase letters, numbers, underscores, or hyphens.\nlabelstringHuman-readable editor label.\ndefault_valuemixedValue used before content is saved. Match the field value type.\nrequiredbooleanRejects an empty option-page submission.\nconditional_logicarrayControls editor visibility based on another field.\nlocationstringdefault or inspector for block fields."
                }
            ]
        }
    ]
}