mirror of
https://github.com/Heretek-AI/heretek-control-core.git
synced 2026-10-12 02:03:55 +00:00
255 lines
6.4 KiB
PHP
255 lines
6.4 KiB
PHP
<?php
|
|
/**
|
|
* Block Store — source of truth and sandbox manager for custom Gutenberg blocks.
|
|
*
|
|
* @package EMCP_Tools
|
|
* @since 3.6.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class EMCP_Tools_Block_Store extends EMCP_Tools_Sandbox_Store {
|
|
|
|
const POST_TYPE = 'emcp_block';
|
|
const META_SPEC = '_emcp_block_spec';
|
|
const META_BLOCK_NAME = '_emcp_block_name';
|
|
const META_CLASS_NAME = '_emcp_class_name';
|
|
const META_LAST_ERROR = '_emcp_last_error';
|
|
|
|
/** @var self|null */
|
|
private static $instance = null;
|
|
|
|
public static function instance(): self {
|
|
if ( null === self::$instance ) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
public function kind(): string {
|
|
return 'block';
|
|
}
|
|
|
|
protected function sandbox_subdir(): string {
|
|
return 'blocks';
|
|
}
|
|
|
|
protected function manifest_filename(): string {
|
|
return 'blocks-manifest.json';
|
|
}
|
|
|
|
public static function init(): void {
|
|
add_action( 'init', array( __CLASS__, 'register_post_type' ), 5 );
|
|
}
|
|
|
|
public static function register_post_type(): void {
|
|
register_post_type(
|
|
self::POST_TYPE,
|
|
array(
|
|
'public' => false,
|
|
'show_ui' => false,
|
|
'supports' => array( 'title' ),
|
|
'capability_type' => 'page',
|
|
'map_meta_cap' => true,
|
|
'exclude_from_search' => true,
|
|
)
|
|
);
|
|
}
|
|
|
|
public function create( array $spec, string $status = 'publish' ) {
|
|
$val = EMCP_Tools_Block_Generator::validate( $spec );
|
|
if ( is_wp_error( $val ) ) {
|
|
return $val;
|
|
}
|
|
|
|
$post_id = wp_insert_post(
|
|
array(
|
|
'post_type' => self::POST_TYPE,
|
|
'post_status' => $status,
|
|
'post_title' => sanitize_text_field( $spec['title'] ),
|
|
),
|
|
true
|
|
);
|
|
|
|
if ( is_wp_error( $post_id ) ) {
|
|
return $post_id;
|
|
}
|
|
|
|
update_post_meta( $post_id, self::META_SPEC, $spec );
|
|
update_post_meta( $post_id, self::META_BLOCK_NAME, sanitize_key( $spec['name'] ) );
|
|
|
|
$compile = $this->compile( $post_id, $spec );
|
|
if ( is_wp_error( $compile ) ) {
|
|
return $compile;
|
|
}
|
|
|
|
$this->rebuild_manifest();
|
|
return $post_id;
|
|
}
|
|
|
|
public function update( int $post_id, array $spec ) {
|
|
$val = EMCP_Tools_Block_Generator::validate( $spec );
|
|
if ( is_wp_error( $val ) ) {
|
|
return $val;
|
|
}
|
|
|
|
$post = get_post( $post_id );
|
|
if ( ! $post || self::POST_TYPE !== $post->post_type ) {
|
|
return new WP_Error( 'not_found', __( 'Block not found.', 'emcp-tools' ) );
|
|
}
|
|
|
|
wp_update_post(
|
|
array(
|
|
'ID' => $post_id,
|
|
'post_title' => sanitize_text_field( $spec['title'] ),
|
|
)
|
|
);
|
|
|
|
update_post_meta( $post_id, self::META_SPEC, $spec );
|
|
update_post_meta( $post_id, self::META_BLOCK_NAME, sanitize_key( $spec['name'] ) );
|
|
|
|
$compile = $this->compile( $post_id, $spec );
|
|
if ( is_wp_error( $compile ) ) {
|
|
return $compile;
|
|
}
|
|
|
|
$this->bump_version( $post_id );
|
|
$this->rebuild_manifest();
|
|
return true;
|
|
}
|
|
|
|
public function compile( int $post_id, array $spec ) {
|
|
$this->ensure_sandbox();
|
|
$dir = $this->artifact_dir( $post_id );
|
|
wp_mkdir_p( $dir );
|
|
|
|
$block_slug = 'emcp-sandbox/' . sanitize_key( $spec['name'] );
|
|
$files = EMCP_Tools_Block_Generator::generate( $spec, $block_slug );
|
|
|
|
$this->write_file( $dir . '/block.json', $files['block_json'] );
|
|
$this->write_file( $dir . '/render.php', $files['render_php'] );
|
|
|
|
return true;
|
|
}
|
|
|
|
public function get( int $post_id ) {
|
|
$post = get_post( $post_id );
|
|
if ( ! $post || self::POST_TYPE !== $post->post_type ) {
|
|
return new WP_Error( 'not_found', __( 'Block not found.', 'emcp-tools' ) );
|
|
}
|
|
|
|
return array(
|
|
'id' => $post->ID,
|
|
'title' => $post->post_title,
|
|
'status' => $post->post_status,
|
|
'name' => get_post_meta( $post->ID, self::META_BLOCK_NAME, true ),
|
|
'spec' => get_post_meta( $post->ID, self::META_SPEC, true ),
|
|
'sync' => $this->sync_meta( $post->ID ),
|
|
);
|
|
}
|
|
|
|
public function list( array $args = array() ): array {
|
|
$query_args = array(
|
|
'post_type' => self::POST_TYPE,
|
|
'post_status' => array( 'publish', 'draft' ),
|
|
'posts_per_page' => 100,
|
|
);
|
|
$posts = get_posts( $query_args );
|
|
$list = array();
|
|
foreach ( $posts as $p ) {
|
|
$item = $this->get( $p->ID );
|
|
if ( ! is_wp_error( $item ) ) {
|
|
$list[] = $item;
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
public function set_status( int $post_id, string $status ): bool {
|
|
$post = get_post( $post_id );
|
|
if ( ! $post || self::POST_TYPE !== $post->post_type ) {
|
|
return false;
|
|
}
|
|
|
|
wp_update_post(
|
|
array(
|
|
'ID' => $post_id,
|
|
'post_status' => $status,
|
|
)
|
|
);
|
|
|
|
$this->rebuild_manifest();
|
|
return true;
|
|
}
|
|
|
|
public function delete( int $post_id ): bool {
|
|
$post = get_post( $post_id );
|
|
if ( ! $post || self::POST_TYPE !== $post->post_type ) {
|
|
return false;
|
|
}
|
|
|
|
$this->rmdir_recursive( $this->artifact_dir( $post_id ) );
|
|
wp_delete_post( $post_id, true );
|
|
$this->rebuild_manifest();
|
|
return true;
|
|
}
|
|
|
|
public function rebuild_manifest(): void {
|
|
$posts = get_posts(
|
|
array(
|
|
'post_type' => self::POST_TYPE,
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => 200,
|
|
)
|
|
);
|
|
|
|
$manifest = array();
|
|
foreach ( $posts as $p ) {
|
|
$manifest[] = array(
|
|
'id' => $p->ID,
|
|
'name' => get_post_meta( $p->ID, self::META_BLOCK_NAME, true ),
|
|
'dir' => $this->artifact_dir( $p->ID ),
|
|
);
|
|
}
|
|
|
|
$this->write_file( $this->manifest_path(), wp_json_encode( $manifest, JSON_PRETTY_PRINT ) );
|
|
}
|
|
|
|
public function checksum( int $id ): string {
|
|
$spec = (array) get_post_meta( $id, self::META_SPEC, true );
|
|
return hash( 'sha256', wp_json_encode( $spec ) );
|
|
}
|
|
|
|
public function to_bundle( int $id ) {
|
|
$post = get_post( $id );
|
|
if ( ! $post || self::POST_TYPE !== $post->post_type ) {
|
|
return new WP_Error( 'not_found', 'Block not found.' );
|
|
}
|
|
$spec = (array) get_post_meta( $id, self::META_SPEC, true );
|
|
$sm = $this->sync_meta( $id );
|
|
return array(
|
|
'kind' => 'block',
|
|
'uuid' => $sm['uuid'],
|
|
'meta' => array(
|
|
'title' => $post->post_title,
|
|
'description' => $post->post_excerpt,
|
|
'author' => (string) ( wp_get_current_user()->user_login ?? '' ),
|
|
'license' => 'GPL-2.0-or-later',
|
|
),
|
|
'spec' => $spec,
|
|
'version' => max( 1, (int) ( $sm['version'] ?? 1 ) ),
|
|
'updated_at' => $sm['updated_at'] ?? gmdate( 'c' ),
|
|
);
|
|
}
|
|
|
|
public function apply_bundle( array $bundle ) {
|
|
$spec = (array) ( $bundle['spec'] ?? array() );
|
|
$name = (string) ( $bundle['meta']['title'] ?? 'Imported Block' );
|
|
return $this->create_block( $name, $spec );
|
|
}
|
|
}
|
|
|
|
EMCP_Tools_Block_Store::init();
|