/ wordpress / restai / includes / class-restai-content.php
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  }