PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.13
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.13
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / assets / php / ai-external-capture.php

ai-external-capture.php in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.13, at assets/php/ai-external-capture.php

73 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /** Session-private screenshots: no public uploads or model credentials. */
3 if ( ! defined( 'ABSPATH' ) ) { exit; }
4 function bkbg_external_render_section( $request ) {
5 $s = bkbg_external_read( $request['session'] );
6 if ( ! $s ) { return bkbg_external_error( 'Session expired.', 410 ); }
7 $content = $request['content'];
8 if ( ! is_string( $content ) || strlen( $content ) > 1000000 ) { return bkbg_external_error( 'Section content is too large.', 413 ); }
9 $blocks = parse_blocks( $content );
10 if ( count( $blocks ) !== 1 || empty( $blocks[0]['blockName'] ) ) { return bkbg_external_error( 'Supply one serialized section.' ); }
11 $previous = $GLOBALS['post'] ?? null;
12 try {
13 $GLOBALS['post'] = get_post( $s['post'] );
14 $html = render_block( $blocks[0] );
15 return array( 'html' => $html, 'themeCss' => function_exists( 'wp_get_global_stylesheet' ) ? wp_get_global_stylesheet() : '' );
16 } finally { $GLOBALS['post'] = $previous; }
17 }
18 function bkbg_external_save_capture( $request ) {
19 $id = $request->get_url_params()['capture'];
20 $data = $request['data'];
21 if ( strlen( $request->get_body() ) > 4300000 || ! is_string( $data ) || strpos( $data, 'data:image/png;base64,' ) !== 0 ) { return bkbg_external_error( 'Supply a PNG screenshot up to 3 MB.', 413 ); }
22 $bytes = base64_decode( substr( $data, 22 ), true );
23 $info = $bytes ? @getimagesizefromstring( $bytes ) : false;
24 if ( ! $info || 'image/png' !== $info['mime'] || $info[0] > 1600 || $info[1] > 6000 || ! in_array( $request['viewport'], array( 'desktop', 'mobile' ), true ) || ! is_string( $request['clientId'] ) || strlen( $request['clientId'] ) > 100 ) { return bkbg_external_error( 'Invalid section screenshot.' ); }
25 $warnings = array_slice( array_filter( (array) $request['warnings'], 'is_string' ), 0, 10 );
26 $record = array( 'data' => base64_encode( $bytes ), 'clientId' => $request['clientId'], 'viewport' => $request['viewport'], 'width' => $info[0], 'height' => $info[1], 'warnings' => array_map( 'sanitize_text_field', $warnings ), 'captured_at' => time(), 'reviewed' => false, 'delivered' => false );
27 return bkbg_external_change( $request['session'], function ( &$s ) use ( $id, $record ) {
28 $captures = $s['captures'] ?? array();
29 if ( isset( $captures[ $id ] ) ) {
30 if ( $captures[ $id ]['data'] !== $record['data'] ) { return bkbg_external_error( 'Capture id already used.', 409 ); }
31 } else {
32 foreach ( $captures as $old_id => $old ) { if ( $old['clientId'] === $record['clientId'] && $old['viewport'] === $record['viewport'] ) { unset( $captures[ $old_id ] ); } }
33 $record['revision'] = $s['visual_revision'] ?? 0;
34 $captures[ $id ] = $record;
35 $s['captures'] = array_slice( $captures, -4, null, true );
36 }
37 return array( 'id' => $id, 'path' => '/captures/' . $id, 'width' => $record['width'], 'height' => $record['height'], 'viewport' => $record['viewport'], 'warnings' => $record['warnings'], 'kind' => 'wordpress-static-render', 'review_required' => true );
38 } );
39 }
40 function bkbg_external_get_capture( $request ) {
41 $s = bkbg_external_read( $request['session'] );
42 $id = $request->get_url_params()['capture'];
43 if ( ! $s ) { return bkbg_external_error( 'Session expired.', 410 ); }
44 if ( empty( $s['captures'][ $id ] ) ) { return bkbg_external_error( 'Screenshot expired. Capture the section again.', 404 ); }
45 $delivery = bkbg_external_change( $request['session'], function ( &$current ) use ( $id ) {
46 if ( empty( $current['captures'][ $id ] ) ) { return bkbg_external_error( 'Screenshot expired.', 404 ); }
47 $current['captures'][ $id ]['delivered'] = true;
48 return true;
49 } );
50 if ( is_wp_error( $delivery ) ) { return $delivery; }
51 return new WP_REST_Response( base64_decode( $s['captures'][ $id ]['data'] ), 200, array( 'Content-Type' => 'image/png', 'X-Content-Type-Options' => 'nosniff', 'Cache-Control' => 'no-store, private' ) );
52 }
53 function bkbg_external_review_capture( $request ) {
54 $ids = $request['capture_ids']; $decision = $request['decision']; $notes = $request['notes'];
55 if ( ! is_array( $ids ) || ! count( $ids ) || count( $ids ) > 4 || array_filter( $ids, function ( $id ) { return ! is_string( $id ); } ) || ! in_array( $decision, array( 'passed', 'needs_changes' ), true ) || ! is_string( $notes ) || ! trim( $notes ) || strlen( $notes ) > 6000 ) { return bkbg_external_error( 'Supply capture_ids, decision (passed or needs_changes), and visual review notes.' ); }
56 return bkbg_external_change( $request['session'], function ( &$s ) use ( $ids, $decision, $notes ) {
57 foreach ( $ids as $id ) {
58 if ( empty( $s['captures'][ $id ] ) || $s['captures'][ $id ]['revision'] !== ( $s['visual_revision'] ?? 0 ) ) { return bkbg_external_error( 'Screenshot is missing or predates the last edit. Capture again before reviewing.', 409 ); }
59 }
60 foreach ( $ids as $id ) { if ( empty( $s['captures'][ $id ]['delivered'] ) ) { return bkbg_external_error( 'Download and open each screenshot before submitting its visual review.', 409 ); } }
61 foreach ( $ids as $id ) { $s['captures'][ $id ]['reviewed'] = $decision; }
62 $s['visual_review'] = array( 'decision' => $decision, 'notes' => sanitize_textarea_field( $notes ), 'updated' => time() );
63 return array( 'ok' => true, 'decision' => $decision );
64 } );
65 }
66 add_filter( 'rest_pre_serve_request', function ( $served, $response, $request ) {
67 if ( preg_match( '#^/blockenberg/v1/ai/external/[a-f0-9]{32}/captures/[a-zA-Z0-9_-]+$#D', $request->get_route() ) && 'GET' === $request->get_method() && 200 === $response->get_status() && ( $response->get_headers()['Content-Type'] ?? '' ) === 'image/png' ) {
68 echo $response->get_data(); // Validated PNG, available only after bearer authorization.
69 return true;
70 }
71 return $served;
72 }, 10, 3 );
73