__( 'Rooster Zero theme', 'ai-eshop-optimizer' ), 'description' => __( 'Read the theme manifest, tokens, templates, patterns, slots and settings; change them through draft, preview, apply and undo.', 'ai-eshop-optimizer' ) ) ); } public static function register() { if ( ! function_exists( 'wp_register_ability' ) ) { return; } $obj = static function ( array $props = array(), array $required = array() ) { return array( 'type' => 'object', 'properties' => $props, 'required' => $required, 'additionalProperties' => true ); }; $read = array( 'readonly' => true, 'idempotent' => true, 'destructive' => false ); $write = array( 'readonly' => false, 'idempotent' => true, 'destructive' => false ); $out = $obj(); $spec = array( 'spec' => $obj( array(), array() ) + array( 'description' => 'A rooster-page@1 spec (the object, not a path).' ) ); $media = array( 'strict' => array( 'type' => 'boolean', 'description' => 'The validator\'s warnings are errors.' ), ); wp_register_ability( self::CATEGORY . '/validate-page', array( 'label' => __( 'Validate a page spec', 'ai-eshop-optimizer' ), 'description' => __( 'Check a rooster-page@1 spec: the shape, the kinds, the keys, the icons, the patterns, the media, the links. Returns errors and warnings.', 'ai-eshop-optimizer' ), 'category' => self::CATEGORY, 'input_schema' => $obj( $spec + $media, array( 'spec' ) ), 'output_schema' => $out, 'execute_callback' => static function ( $input ) { $input = (array) $input; if ( ! is_array( $input['spec'] ?? null ) ) { return new WP_Error( 'aieo_content_no_spec', __( 'spec: the page spec object is required.', 'ai-eshop-optimizer' ), array( 'status' => 400 ) ); } return AIEO_Content_Spec::validate( $input['spec'], AIEO_Content_Compiler::media_defaults() + array( 'check_files' => true ) ); }, 'permission_callback' => array( __CLASS__, 'can_read' ), 'meta' => array( 'annotations' => $read, 'show_in_rest' => true ), ) ); wp_register_ability( self::CATEGORY . '/export-page', array( 'label' => __( 'Export a page as a spec', 'ai-eshop-optimizer' ), 'description' => __( 'A page\'s blocks back to a rooster-page@1 spec. Input: page (the recipe key, the slug or the id).', 'ai-eshop-optimizer' ), 'category' => self::CATEGORY, 'input_schema' => $obj( array( 'page' => array( 'type' => array( 'string', 'integer' ) ) ), array( 'page' ) ), 'output_schema' => $out, 'execute_callback' => static function ( $input ) { return AIEO_Content_Exporter::export( (string) ( ( (array) $input )['page'] ?? '' ) ); }, 'permission_callback' => array( __CLASS__, 'can_read' ), 'meta' => array( 'annotations' => $read, 'show_in_rest' => true ), ) ); wp_register_ability( self::CATEGORY . '/apply-page', array( 'label' => __( 'Apply a page spec', 'ai-eshop-optimizer' ), 'description' => __( 'Compile a rooster-page@1 spec into a page. mode draft (default) writes an autosave and returns a preview link (a new page is created as a draft); mode apply updates the page (a revision) and sets its meta. force: true, or the keys of the sections whose human edits to override.', 'ai-eshop-optimizer' ), 'category' => self::CATEGORY, 'input_schema' => $obj( $spec + $media + array( 'mode' => array( 'type' => 'string', 'enum' => array( 'draft', 'apply' ), 'default' => 'draft' ), 'status' => array( 'type' => 'string', 'enum' => array( 'draft', 'publish' ) ), 'force' => array( 'type' => array( 'boolean', 'array' ), 'items' => array( 'type' => 'string' ) ), 'dry_run' => array( 'type' => 'boolean' ), ), array( 'spec' ) ), 'output_schema' => $out, 'execute_callback' => static function ( $input ) { $input = (array) $input; if ( ! is_array( $input['spec'] ?? null ) ) { return new WP_Error( 'aieo_content_no_spec', __( 'spec: the page spec object is required.', 'ai-eshop-optimizer' ), array( 'status' => 400 ) ); } return AIEO_Content_Compiler::apply( $input['spec'], array( 'mode' => (string) ( $input['mode'] ?? 'draft' ), 'status' => (string) ( $input['status'] ?? '' ), 'force' => $input['force'] ?? false, 'dry_run' => ! empty( $input['dry_run'] ), 'strict' => ! empty( $input['strict'] ), ) ); }, 'permission_callback' => array( __CLASS__, 'can_write' ), 'meta' => array( 'annotations' => $write, 'show_in_rest' => true ), ) ); wp_register_ability( self::CATEGORY . '/apply-menus', array( 'label' => __( 'Apply the menus', 'ai-eshop-optimizer' ), 'description' => __( 'Write a rooster-menus@1 file\'s menus as navigation posts (adopted by slug). mode draft (default) plans without writing; apply writes.', 'ai-eshop-optimizer' ), 'category' => self::CATEGORY, 'input_schema' => $obj( array( 'menus' => $obj(), 'mode' => array( 'type' => 'string', 'enum' => array( 'draft', 'apply' ), 'default' => 'draft' ), 'dry_run' => array( 'type' => 'boolean' ), 'strict' => array( 'type' => 'boolean' ) ), array( 'menus' ) ), 'output_schema' => $out, 'execute_callback' => static function ( $input ) { $input = (array) $input; if ( ! is_array( $input['menus'] ?? null ) ) { return new WP_Error( 'aieo_content_no_menus', __( 'menus: the menus object is required.', 'ai-eshop-optimizer' ), array( 'status' => 400 ) ); } return AIEO_Content_Menus::apply( $input['menus'], array( 'mode' => (string) ( $input['mode'] ?? 'draft' ), 'dry_run' => ! empty( $input['dry_run'] ), 'strict' => ! empty( $input['strict'] ) ) ); }, 'permission_callback' => array( __CLASS__, 'can_write_menus' ), 'meta' => array( 'annotations' => $write, 'show_in_rest' => true ), ) ); } public static function can_read() { return current_user_can( 'edit_pages' ); } public static function can_write() { if ( ! current_user_can( 'edit_pages' ) ) { return false; } if ( defined( 'AIEO_CAPABILITY' ) && ! current_user_can( (string) AIEO_CAPABILITY ) ) { return false; } return true; } public static function can_write_menus() { return current_user_can( 'edit_theme_options' ) && self::can_write(); } }