PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 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 / admin-dashboard.php

admin-dashboard.php in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at assets/php/admin-dashboard.php

385 lines 18.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Blockenberg — Block Manager Dashboard
4 *
5 * WordPress.com-inspired admin page that lets users enable / disable
6 * individual blocks. Disabled blocks are stored in the
7 * 'blockenberg_disabled_blocks' option as a flat array of block names
8 * (e.g. "blockenberg/accordion").
9 *
10 * @package Blockenberg
11 */
12
13 defined( 'ABSPATH' ) || exit;
14
15 /* ──────────────────────────────────────────────
16 * 1. Register admin menu
17 * ────────────────────────────────────────────── */
18 add_action( 'admin_menu', function () {
19 add_menu_page(
20 __( 'Blocks', 'blockenberg' ),
21 __( 'Blockenberg', 'blockenberg' ),
22 'manage_options',
23 'blockenberg',
24 'bkbg_render_dashboard',
25 'dashicons-screenoptions',
26 59
27 );
28 add_submenu_page(
29 'blockenberg',
30 __( 'Blocks', 'blockenberg' ),
31 __( 'Blocks', 'blockenberg' ),
32 'manage_options',
33 'blockenberg',
34 'bkbg_render_dashboard'
35 );
36 } );
37
38 /* ──────────────────────────────────────────────
39 * 2. Enqueue dashboard assets (only on our page)
40 * ────────────────────────────────────────────── */
41 add_action( 'admin_enqueue_scripts', function ( $hook ) {
42 if ( 'toplevel_page_blockenberg' !== $hook ) {
43 return;
44 }
45
46 $plugin_dir = dirname( __DIR__, 2 );
47 $plugin_url = plugins_url( '', $plugin_dir . '/blockenberg.php' );
48
49 wp_enqueue_style(
50 'bkbg-admin-dashboard',
51 $plugin_url . '/assets/css/admin-dashboard.css',
52 array(),
53 filemtime( $plugin_dir . '/assets/css/admin-dashboard.css' )
54 );
55
56 wp_enqueue_script(
57 'bkbg-admin-dashboard',
58 $plugin_url . '/assets/js/admin-dashboard.js',
59 array( 'jquery' ),
60 filemtime( $plugin_dir . '/assets/js/admin-dashboard.js' ),
61 true
62 );
63
64 wp_localize_script( 'bkbg-admin-dashboard', 'bkbgDashboard', array(
65 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
66 'nonce' => wp_create_nonce( 'bkbg_save_blocks' ),
67 'i18n' => array(
68 'saved' => __( 'Settings saved.', 'blockenberg' ),
69 'saving' => __( 'Saving…', 'blockenberg' ),
70 'error' => __( 'Save failed. Please try again.', 'blockenberg' ),
71 'enableAll' => __( 'Enable All', 'blockenberg' ),
72 'disableAll' => __( 'Disable All', 'blockenberg' ),
73 ),
74 ) );
75 } );
76
77 /* ──────────────────────────────────────────────
78 * 3. AJAX handler — save disabled blocks
79 * ────────────────────────────────────────────── */
80 add_action( 'wp_ajax_bkbg_save_disabled_blocks', function () {
81 check_ajax_referer( 'bkbg_save_blocks', 'nonce' );
82
83 if ( ! current_user_can( 'manage_options' ) ) {
84 wp_send_json_error( 'Unauthorized', 403 );
85 }
86
87 $raw = isset( $_POST['disabled'] ) ? $_POST['disabled'] : array();
88
89 if ( is_string( $raw ) ) {
90 $raw = json_decode( stripslashes( $raw ), true );
91 }
92
93 if ( ! is_array( $raw ) ) {
94 $raw = array();
95 }
96
97 $sanitized = array();
98 foreach ( $raw as $block_name ) {
99 $clean = sanitize_text_field( $block_name );
100 if ( '' !== $clean && strpos( $clean, 'blockenberg/' ) === 0 ) {
101 $sanitized[] = $clean;
102 }
103 }
104
105 update_option( 'blockenberg_disabled_blocks', $sanitized, false );
106
107 wp_send_json_success( array(
108 'disabled' => $sanitized,
109 'count' => count( $sanitized ),
110 ) );
111 } );
112
113 /* ──────────────────────────────────────────────
114 * 4. Helper — collect blocks metadata
115 * ────────────────────────────────────────────── */
116 function bkbg_get_all_blocks_meta() {
117 $blocks_dir = dirname( __DIR__, 2 ) . '/blocks';
118 $blocks = array();
119
120 foreach ( glob( $blocks_dir . '/*/block.json' ) as $json_path ) {
121 $raw = file_get_contents( $json_path );
122 if ( ! $raw ) {
123 continue;
124 }
125
126 // WordPress block.json can have trailing commas — strip them.
127 $raw = preg_replace( '/,\s*([\]}])/', '$1', $raw );
128 $data = json_decode( $raw, true );
129 if ( ! is_array( $data ) || empty( $data['name'] ) ) {
130 continue;
131 }
132
133 $blocks[] = array(
134 'name' => $data['name'],
135 'title' => isset( $data['title'] ) ? $data['title'] : basename( dirname( $json_path ) ),
136 'category' => isset( $data['category'] ) ? $data['category'] : 'blockenberg',
137 'icon' => isset( $data['icon'] ) ? $data['icon'] : 'block-default',
138 'keywords' => isset( $data['keywords'] ) ? $data['keywords'] : array(),
139 );
140 }
141
142 // Sort by title.
143 usort( $blocks, function ( $a, $b ) {
144 return strcasecmp( $a['title'], $b['title'] );
145 } );
146
147 return $blocks;
148 }
149
150 /* ──────────────────────────────────────────────
151 * 5. Category labels (mirrors block_categories_all).
152 * ────────────────────────────────────────────── */
153 function bkbg_get_category_labels() {
154 return array(
155 'bkbg-layout' => __( 'Layout & Structure', 'blockenberg' ),
156 'bkbg-content' => __( 'Content & Typography', 'blockenberg' ),
157 'bkbg-media' => __( 'Media & Images', 'blockenberg' ),
158 'bkbg-marketing' => __( 'Marketing & Conversion', 'blockenberg' ),
159 'bkbg-business' => __( 'Business & Services', 'blockenberg' ),
160 'bkbg-blog' => __( 'Blog & Editorial', 'blockenberg' ),
161 'bkbg-interactive' => __( 'Interactive & Games', 'blockenberg' ),
162 'bkbg-charts' => __( 'Charts & Data', 'blockenberg' ),
163 'bkbg-calculators' => __( 'Calculators & Tools', 'blockenberg' ),
164 'bkbg-effects' => __( 'Effects & Animation', 'blockenberg' ),
165 'bkbg-dev' => __( 'Developer Tools', 'blockenberg' ),
166 'blockenberg' => __( 'General', 'blockenberg' ),
167 );
168 }
169
170 /* Category dashicons */
171 function bkbg_get_category_icons() {
172 return array(
173 'bkbg-layout' => 'dashicons-layout',
174 'bkbg-content' => 'dashicons-editor-paragraph',
175 'bkbg-media' => 'dashicons-format-image',
176 'bkbg-marketing' => 'dashicons-megaphone',
177 'bkbg-business' => 'dashicons-building',
178 'bkbg-blog' => 'dashicons-welcome-write-blog',
179 'bkbg-interactive' => 'dashicons-games',
180 'bkbg-charts' => 'dashicons-chart-bar',
181 'bkbg-calculators' => 'dashicons-calculator',
182 'bkbg-effects' => 'dashicons-art',
183 'bkbg-dev' => 'dashicons-code-standards',
184 'blockenberg' => 'dashicons-screenoptions',
185 );
186 }
187
188 /* ──────────────────────────────────────────────
189 * 6. Render the dashboard page
190 * ────────────────────────────────────────────── */
191 function bkbg_render_dashboard() {
192 $blocks = bkbg_get_all_blocks_meta();
193 $disabled = get_option( 'blockenberg_disabled_blocks', array() );
194 $category_labels = bkbg_get_category_labels();
195 $category_icons = bkbg_get_category_icons();
196
197 if ( ! is_array( $disabled ) ) {
198 $disabled = array();
199 }
200
201 // Group blocks by category.
202 $by_category = array();
203 foreach ( $blocks as $block ) {
204 $cat = $block['category'];
205 if ( ! isset( $by_category[ $cat ] ) ) {
206 $by_category[ $cat ] = array();
207 }
208 $by_category[ $cat ][] = $block;
209 }
210
211 // Sort categories in the same order as $category_labels.
212 $ordered = array();
213 foreach ( array_keys( $category_labels ) as $cat_slug ) {
214 if ( isset( $by_category[ $cat_slug ] ) ) {
215 $ordered[ $cat_slug ] = $by_category[ $cat_slug ];
216 }
217 }
218 // Append any unknown categories.
219 foreach ( $by_category as $cat_slug => $cat_blocks ) {
220 if ( ! isset( $ordered[ $cat_slug ] ) ) {
221 $ordered[ $cat_slug ] = $cat_blocks;
222 }
223 }
224
225 $total_blocks = count( $blocks );
226 $enabled_blocks = $total_blocks - count( $disabled );
227 ?>
228 <div id="bkbg-dashboard" class="bkbg-dashboard">
229
230 <!-- ▸ Header -->
231 <header class="bkbg-header">
232 <div class="bkbg-header__left">
233 <div class="bkbg-header__brand">
234 <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="2" y="2" width="8" height="8" rx="2"/><rect x="14" y="2" width="8" height="8" rx="2"/><rect x="2" y="14" width="8" height="8" rx="2"/><rect x="14" y="14" width="8" height="8" rx="2"/></svg>
235 <span>blockenberg.</span>
236 </div>
237 <div class="bkbg-header__text">
238 <h1><?php esc_html_e( 'Blocks', 'blockenberg' ); ?></h1>
239 <p class="bkbg-header__subtitle">
240 <?php
241 printf(
242 /* translators: 1: enabled count 2: total count */
243 esc_html__( '%1$s of %2$s blocks enabled', 'blockenberg' ),
244 '<span id="bkbg-enabled-count">' . intval( $enabled_blocks ) . '</span>',
245 '<span id="bkbg-total-count">' . intval( $total_blocks ) . '</span>'
246 );
247 ?>
248 </p>
249 </div>
250 </div>
251 <div class="bkbg-header__right">
252 <nav class="bkbg-header__links" aria-label="<?php esc_attr_e( 'Blockenberg resources', 'blockenberg' ); ?>">
253 <a href="<?php echo esc_url( admin_url( 'admin.php?page=blockenberg-templates' ) ); ?>"><?php esc_html_e( 'Template Library', 'blockenberg' ); ?></a>
254 <a href="<?php echo esc_url( admin_url( 'admin.php?page=blockenberg-ai' ) ); ?>"><?php esc_html_e( 'AI Agent Settings', 'blockenberg' ); ?></a>
255 <a href="https://blockenberg.com/docs/" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Docs', 'blockenberg' ); ?> ↗</a>
256 </nav>
257 <div class="bkbg-header__controls">
258 <div class="bkbg-search-wrap">
259 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="10" cy="10" r="6.5"/><path d="m15 15 5 5"/></svg>
260 <input type="text" id="bkbg-search" class="bkbg-search"
261 aria-label="<?php esc_attr_e( 'Search blocks', 'blockenberg' ); ?>"
262 placeholder="<?php esc_attr_e( 'Search blocks…', 'blockenberg' ); ?>"
263 autocomplete="off" />
264 </div>
265 <button type="button" id="bkbg-save" class="bkbg-btn bkbg-btn--primary">
266 <span class="dashicons dashicons-cloud-saved"></span>
267 <?php esc_html_e( 'Save Changes', 'blockenberg' ); ?>
268 </button>
269 </div>
270 </div>
271 </header>
272
273 <!-- ▸ Toolbar -->
274 <div class="bkbg-workspace">
275 <aside class="bkbg-toolbar" aria-label="<?php esc_attr_e( 'Block categories', 'blockenberg' ); ?>">
276 <p class="bkbg-toolbar__label"><?php esc_html_e( 'Categories', 'blockenberg' ); ?></p>
277 <div class="bkbg-toolbar__tabs" id="bkbg-category-tabs">
278 <button type="button" class="bkbg-tab bkbg-tab--active" data-category="all" aria-pressed="true">
279 <?php esc_html_e( 'All Blocks', 'blockenberg' ); ?>
280 <span class="bkbg-tab__count"><?php echo intval( $total_blocks ); ?></span>
281 </button>
282 <?php foreach ( $ordered as $cat_slug => $cat_blocks ) :
283 $label = isset( $category_labels[ $cat_slug ] ) ? $category_labels[ $cat_slug ] : $cat_slug;
284 $icon = isset( $category_icons[ $cat_slug ] ) ? $category_icons[ $cat_slug ] : 'dashicons-block-default';
285 ?>
286 <button type="button" class="bkbg-tab" data-category="<?php echo esc_attr( $cat_slug ); ?>" aria-pressed="false">
287 <span class="dashicons <?php echo esc_attr( $icon ); ?>"></span>
288 <?php echo esc_html( $label ); ?>
289 <span class="bkbg-tab__count"><?php echo count( $cat_blocks ); ?></span>
290 </button>
291 <?php endforeach; ?>
292 </div>
293 <div class="bkbg-toolbar__actions">
294 <button type="button" id="bkbg-enable-all" class="bkbg-btn bkbg-btn--ghost">
295 <?php esc_html_e( 'Enable All', 'blockenberg' ); ?>
296 </button>
297 <button type="button" id="bkbg-disable-all" class="bkbg-btn bkbg-btn--ghost bkbg-btn--danger">
298 <?php esc_html_e( 'Disable All', 'blockenberg' ); ?>
299 </button>
300 </div>
301 </aside>
302
303 <!-- ▸ Toast notification -->
304 <div id="bkbg-toast" class="bkbg-toast" aria-live="polite"></div>
305
306 <main class="bkbg-workspace__content" aria-label="<?php esc_attr_e( 'Available blocks', 'blockenberg' ); ?>">
307 <!-- ▸ Block grid -->
308 <div class="bkbg-grid" id="bkbg-grid">
309 <?php foreach ( $ordered as $cat_slug => $cat_blocks ) :
310 $label = isset( $category_labels[ $cat_slug ] ) ? $category_labels[ $cat_slug ] : $cat_slug;
311 ?>
312 <div class="bkbg-category-section" data-category="<?php echo esc_attr( $cat_slug ); ?>">
313 <div class="bkbg-category-header">
314 <h2 class="bkbg-category-title">
315 <?php
316 $icon = isset( $category_icons[ $cat_slug ] ) ? $category_icons[ $cat_slug ] : 'dashicons-block-default';
317 ?>
318 <span class="dashicons <?php echo esc_attr( $icon ); ?>"></span>
319 <?php echo esc_html( $label ); ?>
320 <span class="bkbg-category-count"><?php echo count( $cat_blocks ); ?></span>
321 </h2>
322 <div class="bkbg-category-actions">
323 <button type="button" class="bkbg-cat-toggle" data-action="enable" data-cat="<?php echo esc_attr( $cat_slug ); ?>">
324 <?php esc_html_e( 'Enable All', 'blockenberg' ); ?>
325 </button>
326 <span class="bkbg-cat-sep">|</span>
327 <button type="button" class="bkbg-cat-toggle" data-action="disable" data-cat="<?php echo esc_attr( $cat_slug ); ?>">
328 <?php esc_html_e( 'Disable All', 'blockenberg' ); ?>
329 </button>
330 </div>
331 </div>
332 <div class="bkbg-cards">
333 <?php foreach ( $cat_blocks as $block ) :
334 $is_disabled = in_array( $block['name'], $disabled, true );
335 $slug = str_replace( 'blockenberg/', '', $block['name'] );
336 $dashicon = $block['icon'];
337
338 // Ensure icon is a simple dashicon string (not an object).
339 if ( is_array( $dashicon ) ) {
340 $dashicon = isset( $dashicon['src'] ) ? $dashicon['src'] : 'block-default';
341 }
342
343 // Normalise icon class.
344 if ( strpos( $dashicon, 'dashicons-' ) !== 0 ) {
345 $dashicon = 'dashicons-' . $dashicon;
346 }
347 ?>
348 <div class="bkbg-card <?php echo $is_disabled ? 'bkbg-card--disabled' : ''; ?>"
349 data-block="<?php echo esc_attr( $block['name'] ); ?>"
350 data-title="<?php echo esc_attr( strtolower( $block['title'] ) ); ?>"
351 data-slug="<?php echo esc_attr( $slug ); ?>"
352 data-keywords="<?php echo esc_attr( strtolower( implode( ' ', $block['keywords'] ) ) ); ?>">
353 <div class="bkbg-card__icon">
354 <span class="dashicons <?php echo esc_attr( $dashicon ); ?>"></span>
355 </div>
356 <div class="bkbg-card__info">
357 <span class="bkbg-card__title"><?php echo esc_html( $block['title'] ); ?></span>
358 </div>
359 <label class="bkbg-toggle">
360 <input type="checkbox"
361 class="bkbg-toggle__input"
362 aria-label="<?php echo esc_attr( sprintf( __( 'Enable %s', 'blockenberg' ), $block['title'] ) ); ?>"
363 data-block="<?php echo esc_attr( $block['name'] ); ?>"
364 <?php checked( ! $is_disabled ); ?> />
365 <span class="bkbg-toggle__slider"></span>
366 </label>
367 </div>
368 <?php endforeach; ?>
369 </div>
370 </div>
371 <?php endforeach; ?>
372 </div>
373
374 <!-- ▸ Empty state for search -->
375 <div id="bkbg-empty" class="bkbg-empty" style="display:none;">
376 <span class="dashicons dashicons-search"></span>
377 <p><?php esc_html_e( 'No blocks match your search.', 'blockenberg' ); ?></p>
378 </div>
379 </main>
380 </div>
381
382 </div>
383 <?php
384 }
385