class-restai-content.php
1 <?php 2 /** 3 * Content generation glue + Gutenberg block registration. 4 * 5 * @package RESTai 6 */ 7 8 namespace RESTai; 9 10 if ( ! defined( 'ABSPATH' ) ) { 11 exit; 12 } 13 14 class Content { 15 16 /** @var Client */ 17 private $client; 18 19 public function __construct( Client $client ) { 20 $this->client = $client; 21 add_action( 'init', array( $this, 'register_block' ) ); 22 add_shortcode( 'restai_generate', array( $this, 'shortcode' ) ); 23 } 24 25 /** 26 * Register the "RESTai Content" Gutenberg block. 27 */ 28 public function register_block() { 29 if ( ! function_exists( 'register_block_type' ) ) { 30 return; 31 } 32 register_block_type( 33 'restai/content-generator', 34 array( 35 'api_version' => 2, 36 'title' => __( 'RESTai: Generated Content', 'restai' ), 37 'category' => 'widgets', 38 // Icon is set in JS via blocks/content-generator/index.js so we 39 // can use a custom brain SVG (Dashicons has no brain glyph). 40 'icon' => 'admin-customizer', 41 'editor_script' => 'restai-block-content', 42 'render_callback' => array( $this, 'render_block' ), 43 'attributes' => array( 44 'task' => array( 'type' => 'string', 'default' => 'content_writer' ), 45 'prompt' => array( 'type' => 'string', 'default' => '' ), 46 'cache' => array( 'type' => 'boolean', 'default' => true ), 47 ), 48 ) 49 ); 50 51 wp_register_script( 52 'restai-block-content', 53 RESTAI_PLUGIN_URL . 'blocks/content-generator/index.js', 54 array( 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-components', 'wp-block-editor' ), 55 RESTAI_VERSION, 56 true 57 ); 58 } 59 60 /** 61 * Server-side render — calls RESTai with the configured prompt. 62 * 63 * Caches per (post_id, task, prompt) in transients to avoid re-billing on 64 * every page load. 65 */ 66 public function render_block( $attrs ) { 67 $task = isset( $attrs['task'] ) ? sanitize_key( $attrs['task'] ) : 'content_writer'; 68 $prompt = isset( $attrs['prompt'] ) ? (string) $attrs['prompt'] : ''; 69 $cache = ! isset( $attrs['cache'] ) || $attrs['cache']; 70 71 if ( empty( $prompt ) ) { 72 return '<!-- restai: missing prompt -->'; 73 } 74 75 $key = 'restai_blk_' . md5( $task . '|' . $prompt ); 76 if ( $cache ) { 77 $cached = get_transient( $key ); 78 if ( false !== $cached ) { 79 return $cached; 80 } 81 } 82 83 $plugin = Plugin::instance(); 84 $project_id = $plugin->provisioner->project_for( $task ); 85 if ( $project_id <= 0 ) { 86 return '<!-- restai: no project mapped for ' . esc_html( $task ) . ' -->'; 87 } 88 89 $answer = $this->client->ask( $project_id, $prompt ); 90 if ( is_wp_error( $answer ) ) { 91 return '<!-- restai error: ' . esc_html( $answer->get_error_message() ) . ' -->'; 92 } 93 94 if ( $cache ) { 95 set_transient( $key, $answer, DAY_IN_SECONDS ); 96 } 97 return $answer; 98 } 99 100 /** 101 * [restai_generate task="content_writer" prompt="…"] shortcode. 102 */ 103 public function shortcode( $atts ) { 104 $atts = shortcode_atts( 105 array( 106 'task' => 'content_writer', 107 'prompt' => '', 108 'cache' => '1', 109 ), 110 $atts, 111 'restai_generate' 112 ); 113 return $this->render_block( 114 array( 115 'task' => $atts['task'], 116 'prompt' => $atts['prompt'], 117 'cache' => '1' === (string) $atts['cache'], 118 ) 119 ); 120 } 121 }