PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / trunk
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback vtrunk
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / third-party / page-builder / bricks / class-avcf-abilities-bricks.php
atarim-visual-collaboration / third-party / page-builder / bricks Last commit date
class-avcf-abilities-bricks-pro.php 4 weeks ago class-avcf-abilities-bricks.php 4 weeks ago class-avcf-bricks-detector.php 4 weeks ago class-avcf-bricks-helpers.php 4 weeks ago
class-avcf-abilities-bricks.php
343 lines
1 <?php
2 /**
3 * Bricks — MCP abilities (core: content tree + page settings).
4 *
5 * The stable, load-bearing surface: read/edit the flat element array Bricks
6 * stores per area (content/header/footer), list element types, and read/write
7 * page settings. The deeper Bricks surfaces (global classes, components, theme
8 * styles, variables, interactions, dynamic data, templates) are a separate
9 * advanced pass — they are site-wide / internal-heavy, like Elementor Pro's
10 * advanced set.
11 *
12 * Built on the documented Bricks storage model (read from the Novamira
13 * reference); NOT runtime-tested here. Bricks' own validation engine and
14 * code-element signing are not reproduced — code elements are written UNSIGNED
15 * (Bricks won't execute unsigned code; signing is the excluded execute-PHP
16 * risk class).
17 *
18 * @package atarim-visual-collaboration
19 */
20
21 if ( ! defined('ABSPATH') ) {
22 exit;
23 }
24
25 class AVCF_Abilities_Bricks extends AVCF_Abilities_Base {
26
27 /** @var AVCF_Bricks_Detector */
28 private $detector;
29
30 public function __construct() {
31 $this->detector = new AVCF_Bricks_Detector();
32 }
33
34 public function register() {
35 if ( ! $this->detector->avcf_bricks_is_available() ) {
36 return;
37 }
38 $this->register_check_setup();
39 $this->register_list_elements();
40 $this->register_get_content();
41 $this->register_set_content();
42 $this->register_insert_content();
43 $this->register_patch_elements();
44 $this->register_remove_content();
45 $this->register_settings();
46 }
47
48 /* ------------------------------ shared ----------------------------- */
49
50 private function ro_meta() {
51 return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => true, 'destructive' => false, 'idempotent' => true ] ];
52 }
53 private function write_meta( $destructive = false ) {
54 return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => false, 'destructive' => (bool) $destructive, 'idempotent' => false ] ];
55 }
56 private function std_out() {
57 return [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ];
58 }
59 private function can_edit( $post_id ) {
60 return current_user_can( 'edit_post', (int) $post_id ) || current_user_can( 'edit_posts' );
61 }
62 private function require_post( $post_id ) {
63 if ( $post_id <= 0 || ! get_post( $post_id ) ) { return [ 'success' => false, 'message' => 'A valid post_id is required.' ]; }
64 return null;
65 }
66 private function area_prop() {
67 return [ 'type' => 'string', 'enum' => [ 'content', 'header', 'footer' ], 'default' => 'content', 'description' => 'Which Bricks area to target.' ];
68 }
69
70 /* --------------------------- check-setup --------------------------- */
71
72 private function register_check_setup() {
73 $d = $this->detector;
74 wp_register_ability( 'atarim/bricks-check-setup', [
75 'label' => 'Check Bricks Setup', 'category' => 'atarim',
76 'description' => 'Call first before other Bricks abilities. Reports whether Bricks is active and its version.',
77 'input_schema' => [ 'type' => 'object', 'properties' => [], 'additionalProperties' => false ],
78 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'active' => [ 'type' => 'boolean' ], 'version' => [ 'type' => 'string' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'active', 'message' ] ],
79 'execute_callback' => function( $input = [] ) use ( $d ) {
80 return [ 'success' => true, 'active' => $d->avcf_bricks_is_available(), 'version' => $d->avcf_bricks_version(), 'message' => 'OK.' ];
81 },
82 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
83 'meta' => $this->ro_meta(),
84 ] );
85 }
86
87 /* --------------------------- list-elements ------------------------- */
88
89 private function register_list_elements() {
90 wp_register_ability( 'atarim/bricks-list-elements', [
91 'label' => 'List Bricks Elements', 'category' => 'atarim',
92 'description' => 'List the registered Bricks element types (name + label) — the values you pass as "name" when inserting elements (e.g. "section", "container", "heading", "text", "image", "button").',
93 'input_schema' => [ 'type' => 'object', 'properties' => [], 'additionalProperties' => false ],
94 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'elements' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
95 'execute_callback' => function( $input = [] ) {
96 $types = AVCF_Bricks_Helpers::element_types();
97 return [ 'success' => true, 'elements' => $types, 'message' => $types ? sprintf( '%d element type(s).', count( $types ) ) : 'Element registry not available on this build.' ];
98 },
99 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
100 'meta' => $this->ro_meta(),
101 ] );
102 }
103
104 /* --------------------------- get-content --------------------------- */
105
106 private function register_get_content() {
107 $self = $this;
108 wp_register_ability( 'atarim/bricks-get-content', [
109 'label' => 'Get Bricks Content', 'category' => 'atarim',
110 'description' => 'Read a post\'s Bricks element structure for an area. Bricks stores a FLAT element list — each node has id, name (type), parent (parent id, 0 = top level), children (child ids), and settings. By default returns a structural summary (no settings); pass element_id for one element\'s full data, or include_settings:true for the whole area with settings.',
111 'input_schema' => [ 'type' => 'object', 'properties' => [
112 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
113 'area' => $self->area_prop(),
114 'element_id' => [ 'type' => 'string' ],
115 'include_settings' => [ 'type' => 'boolean', 'default' => false ],
116 ], 'required' => [ 'post_id' ], 'additionalProperties' => false ],
117 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'elements' => [ 'type' => 'array' ], 'element' => [ 'type' => 'object' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
118 'execute_callback' => function( $input = [] ) use ( $self ) {
119 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
120 $area = isset( $input['area'] ) ? (string) $input['area'] : 'content';
121 $els = AVCF_Bricks_Helpers::read_area( $post_id, $area );
122 if ( ! empty( $input['element_id'] ) ) {
123 $el = AVCF_Bricks_Helpers::find( $els, (string) $input['element_id'] );
124 if ( $el === null ) { return [ 'success' => false, 'message' => sprintf( 'Element "%s" not found in %s.', $input['element_id'], $area ) ]; }
125 return [ 'success' => true, 'element' => $el, 'message' => 'OK.' ];
126 }
127 if ( ! empty( $input['include_settings'] ) ) {
128 return [ 'success' => true, 'elements' => $els, 'message' => 'OK (full).' ];
129 }
130 return [ 'success' => true, 'elements' => AVCF_Bricks_Helpers::summarize( $els ), 'message' => 'OK (summary).' ];
131 },
132 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
133 'meta' => $this->ro_meta(),
134 ] );
135 }
136
137 /* --------------------------- set-content --------------------------- */
138
139 private function register_set_content() {
140 $self = $this;
141 wp_register_ability( 'atarim/bricks-set-content', [
142 'label' => 'Set Bricks Content', 'category' => 'atarim',
143 'description' => 'Replace a post\'s ENTIRE Bricks element list for an area with the supplied flat array (same shape get-content returns with include_settings:true). Full overwrite — for targeted changes prefer insert-content / patch-elements / remove-content. Missing ids/children are filled in. Code elements are stored UNSIGNED and will not execute until signed in the Bricks editor.',
144 'input_schema' => [ 'type' => 'object', 'properties' => [
145 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
146 'area' => $self->area_prop(),
147 'elements' => [ 'type' => 'array' ],
148 ], 'required' => [ 'post_id', 'elements' ], 'additionalProperties' => false ],
149 'output_schema'=> $this->std_out(),
150 'execute_callback' => function( $input = [] ) use ( $self ) {
151 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
152 if ( ! $self->can_edit( $post_id ) ) { return [ 'success' => false, 'message' => 'No permission to edit this post.' ]; }
153 if ( ! isset( $input['elements'] ) || ! is_array( $input['elements'] ) ) { return [ 'success' => false, 'message' => 'elements must be an array.' ]; }
154 $area = isset( $input['area'] ) ? (string) $input['area'] : 'content';
155 if ( ! AVCF_Bricks_Helpers::write_area( $post_id, $area, $input['elements'] ) ) { return [ 'success' => false, 'message' => 'Failed to save (no change or write error).' ]; }
156 return [ 'success' => true, 'message' => sprintf( 'Replaced Bricks %s on post %d.', $area, $post_id ) ];
157 },
158 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
159 'meta' => $this->write_meta( true ),
160 ] );
161 }
162
163 /* -------------------------- insert-content ------------------------- */
164
165 private function register_insert_content() {
166 $self = $this;
167 wp_register_ability( 'atarim/bricks-insert-content', [
168 'label' => 'Insert Bricks Element', 'category' => 'atarim',
169 'description' => 'Insert a new element into a post\'s Bricks area. name is the element type (see list-elements). parent_id nests it under an existing element (omit/0 for top level); the parent/children pointers are kept in sync. settings is the element\'s control values. Returns the new element id. Code elements are stored UNSIGNED.',
170 'input_schema' => [ 'type' => 'object', 'properties' => [
171 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
172 'area' => $self->area_prop(),
173 'name' => [ 'type' => 'string', 'description' => 'Element type, e.g. "section", "container", "heading".' ],
174 'parent_id' => [ 'type' => 'string', 'description' => 'Parent element id. Omit for top level.' ],
175 'settings' => [ 'type' => 'object' ],
176 'label' => [ 'type' => 'string' ],
177 ], 'required' => [ 'post_id', 'name' ], 'additionalProperties' => false ],
178 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'element_id' => [ 'type' => 'string' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
179 'execute_callback' => function( $input = [] ) use ( $self ) {
180 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
181 if ( ! $self->can_edit( $post_id ) ) { return [ 'success' => false, 'message' => 'No permission to edit this post.' ]; }
182 $area = isset( $input['area'] ) ? (string) $input['area'] : 'content';
183 $node = [
184 'id' => AVCF_Bricks_Helpers::generate_id(),
185 'name' => (string) $input['name'],
186 'settings' => isset( $input['settings'] ) && is_array( $input['settings'] ) ? $input['settings'] : [],
187 'children' => [],
188 ];
189 if ( isset( $input['label'] ) ) { $node['label'] = (string) $input['label']; }
190 $els = AVCF_Bricks_Helpers::read_area( $post_id, $area );
191 list( $els, $ok ) = AVCF_Bricks_Helpers::insert( $els, isset( $input['parent_id'] ) ? (string) $input['parent_id'] : 0, $node );
192 if ( ! $ok ) { return [ 'success' => false, 'message' => sprintf( 'parent_id "%s" not found.', isset( $input['parent_id'] ) ? $input['parent_id'] : '' ) ]; }
193 if ( ! AVCF_Bricks_Helpers::write_area( $post_id, $area, $els ) ) { return [ 'success' => false, 'message' => 'Failed to save.' ]; }
194 return [ 'success' => true, 'element_id' => $node['id'], 'message' => sprintf( 'Inserted "%s".', $node['name'] ) ];
195 },
196 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
197 'meta' => $this->write_meta( false ),
198 ] );
199 }
200
201 /* -------------------------- patch-elements ------------------------- */
202
203 private function register_patch_elements() {
204 $self = $this;
205 wp_register_ability( 'atarim/bricks-patch-elements', [
206 'label' => 'Patch Bricks Element', 'category' => 'atarim',
207 'description' => 'Update one element by id. settings are shallow-merged into the element\'s existing settings (top-level keys you send overwrite; others kept). Optionally change label/name. Read the element first with get-content (element_id).',
208 'input_schema' => [ 'type' => 'object', 'properties' => [
209 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
210 'area' => $self->area_prop(),
211 'element_id' => [ 'type' => 'string' ],
212 'settings' => [ 'type' => 'object' ],
213 'label' => [ 'type' => 'string' ],
214 'name' => [ 'type' => 'string' ],
215 ], 'required' => [ 'post_id', 'element_id' ], 'additionalProperties' => false ],
216 'output_schema'=> $this->std_out(),
217 'execute_callback' => function( $input = [] ) use ( $self ) {
218 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
219 if ( ! $self->can_edit( $post_id ) ) { return [ 'success' => false, 'message' => 'No permission to edit this post.' ]; }
220 $area = isset( $input['area'] ) ? (string) $input['area'] : 'content';
221 $patch = [];
222 foreach ( [ 'settings', 'label', 'name' ] as $k ) { if ( isset( $input[ $k ] ) ) { $patch[ $k ] = $input[ $k ]; } }
223 if ( empty( $patch ) ) { return [ 'success' => false, 'message' => 'Provide at least one of settings, label, name.' ]; }
224 $els = AVCF_Bricks_Helpers::read_area( $post_id, $area );
225 $found = false;
226 $els = AVCF_Bricks_Helpers::patch( $els, (string) $input['element_id'], $patch, $found );
227 if ( ! $found ) { return [ 'success' => false, 'message' => sprintf( 'Element "%s" not found.', $input['element_id'] ) ]; }
228 if ( ! AVCF_Bricks_Helpers::write_area( $post_id, $area, $els ) ) { return [ 'success' => false, 'message' => 'Failed to save.' ]; }
229 return [ 'success' => true, 'message' => sprintf( 'Updated element "%s".', $input['element_id'] ) ];
230 },
231 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
232 'meta' => $this->write_meta( false ),
233 ] );
234 }
235
236 /* -------------------------- remove-content ------------------------- */
237
238 private function register_remove_content() {
239 $self = $this;
240 wp_register_ability( 'atarim/bricks-remove-content', [
241 'label' => 'Remove Bricks Element', 'category' => 'atarim',
242 'description' => 'Remove an element (and all its descendants) from a Bricks area by id, detaching it from its parent. Dry run unless confirm:true.',
243 'input_schema' => [ 'type' => 'object', 'properties' => [
244 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
245 'area' => $self->area_prop(),
246 'element_id' => [ 'type' => 'string' ],
247 'confirm' => [ 'type' => 'boolean', 'default' => false ],
248 ], 'required' => [ 'post_id', 'element_id' ], 'additionalProperties' => false ],
249 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'removed' => [ 'type' => 'boolean' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
250 'execute_callback' => function( $input = [] ) use ( $self ) {
251 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
252 if ( ! $self->can_edit( $post_id ) ) { return [ 'success' => false, 'message' => 'No permission to edit this post.' ]; }
253 $area = isset( $input['area'] ) ? (string) $input['area'] : 'content';
254 $els = AVCF_Bricks_Helpers::read_area( $post_id, $area );
255 if ( AVCF_Bricks_Helpers::find( $els, (string) $input['element_id'] ) === null ) { return [ 'success' => false, 'message' => sprintf( 'Element "%s" not found.', $input['element_id'] ) ]; }
256 if ( empty( $input['confirm'] ) ) { return [ 'success' => true, 'removed' => false, 'message' => sprintf( 'Dry run: would remove "%s" and its descendants. Re-call with confirm:true.', $input['element_id'] ) ]; }
257 list( $els, $ok ) = AVCF_Bricks_Helpers::remove( $els, (string) $input['element_id'] );
258 if ( ! $ok || ! AVCF_Bricks_Helpers::write_area( $post_id, $area, $els ) ) { return [ 'success' => false, 'message' => 'Failed to remove/save.' ]; }
259 return [ 'success' => true, 'removed' => true, 'message' => sprintf( 'Removed "%s".', $input['element_id'] ) ];
260 },
261 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
262 'meta' => $this->write_meta( true ),
263 ] );
264 }
265
266 /* ------------------------------ settings --------------------------- */
267
268 private function register_settings() {
269 $self = $this; $std = $this->std_out();
270
271 wp_register_ability( 'atarim/bricks-get-settings', [
272 'label' => 'Get Bricks Page Settings', 'category' => 'atarim',
273 'description' => 'Read a post\'s Bricks page settings (the _bricks_page_settings meta — page-level options like SEO, layout, code).',
274 'input_schema' => [ 'type' => 'object', 'properties' => [ 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'post_id' ], 'additionalProperties' => false ],
275 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'settings' => [ 'type' => 'object' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
276 'execute_callback' => function( $input = [] ) use ( $self ) {
277 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
278 $s = get_post_meta( $post_id, '_bricks_page_settings', true );
279 return [ 'success' => true, 'settings' => is_array( $s ) ? $s : [], 'message' => 'OK.' ];
280 },
281 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
282 'meta' => $this->ro_meta(),
283 ] );
284
285 wp_register_ability( 'atarim/bricks-list-settings', [
286 'label' => 'List Bricks Page Setting Keys', 'category' => 'atarim',
287 'description' => 'List the keys present in a post\'s Bricks page settings.',
288 'input_schema' => [ 'type' => 'object', 'properties' => [ 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'post_id' ], 'additionalProperties' => false ],
289 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'keys' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
290 'execute_callback' => function( $input = [] ) use ( $self ) {
291 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
292 $s = get_post_meta( $post_id, '_bricks_page_settings', true );
293 $keys = is_array( $s ) ? array_keys( $s ) : [];
294 return [ 'success' => true, 'keys' => $keys, 'message' => sprintf( '%d key(s).', count( $keys ) ) ];
295 },
296 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
297 'meta' => $this->ro_meta(),
298 ] );
299
300 wp_register_ability( 'atarim/bricks-set-settings', [
301 'label' => 'Set Bricks Page Settings', 'category' => 'atarim',
302 'description' => 'Update a post\'s Bricks page settings. settings is shallow-merged into the existing page settings by default; pass replace:true to overwrite the whole object.',
303 'input_schema' => [ 'type' => 'object', 'properties' => [
304 'post_id' => [ 'type' => 'integer', 'minimum' => 1 ],
305 'settings' => [ 'type' => 'object' ],
306 'replace' => [ 'type' => 'boolean', 'default' => false ],
307 ], 'required' => [ 'post_id', 'settings' ], 'additionalProperties' => false ],
308 'output_schema'=> $std,
309 'execute_callback' => function( $input = [] ) use ( $self ) {
310 $post_id = (int) $input['post_id']; $err = $self->require_post( $post_id ); if ( $err ) { return $err; }
311 if ( ! $self->can_edit( $post_id ) ) { return [ 'success' => false, 'message' => 'No permission to edit this post.' ]; }
312 if ( ! isset( $input['settings'] ) || ! is_array( $input['settings'] ) ) { return [ 'success' => false, 'message' => 'settings must be an object.' ]; }
313 $new = $input['settings'];
314 if ( empty( $input['replace'] ) ) {
315 $cur = get_post_meta( $post_id, '_bricks_page_settings', true );
316 $new = array_merge( is_array( $cur ) ? $cur : [], $new );
317 }
318 update_post_meta( $post_id, '_bricks_page_settings', $new );
319 return [ 'success' => true, 'message' => 'Page settings updated.' ];
320 },
321 'permission_callback' => function() { return current_user_can( 'edit_posts' ); },
322 'meta' => $this->write_meta( false ),
323 ] );
324
325 wp_register_ability( 'atarim/bricks-set-post-types', [
326 'label' => 'Set Bricks Post Types', 'category' => 'atarim',
327 'description' => 'SITE-WIDE. Set which post types the Bricks builder is enabled for (writes the postTypes key in Bricks global settings). post_types is the full array of post type slugs to enable.',
328 'input_schema' => [ 'type' => 'object', 'properties' => [ 'post_types' => [ 'type' => 'array', 'items' => [ 'type' => 'string' ] ] ], 'required' => [ 'post_types' ], 'additionalProperties' => false ],
329 'output_schema'=> $std,
330 'execute_callback' => function( $input = [] ) {
331 $pts = isset( $input['post_types'] ) && is_array( $input['post_types'] ) ? array_values( array_map( 'sanitize_key', $input['post_types'] ) ) : [];
332 $opt = get_option( 'bricks_global_settings' );
333 if ( ! is_array( $opt ) ) { $opt = []; }
334 $opt['postTypes'] = $pts;
335 update_option( 'bricks_global_settings', $opt );
336 return [ 'success' => true, 'message' => sprintf( 'Bricks enabled for %d post type(s).', count( $pts ) ) ];
337 },
338 'permission_callback' => function() { return current_user_can( 'manage_options' ); },
339 'meta' => $this->write_meta( false ),
340 ] );
341 }
342 }
343