@mytechtoday/augment-extensions 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/augment-extensions/domain-rules/wordpress/README.md +163 -0
  2. package/augment-extensions/domain-rules/wordpress/module.json +32 -0
  3. package/augment-extensions/domain-rules/wordpress/rules/coding-standards.md +617 -0
  4. package/augment-extensions/domain-rules/wordpress/rules/directory-structure.md +270 -0
  5. package/augment-extensions/domain-rules/wordpress/rules/file-patterns.md +423 -0
  6. package/augment-extensions/domain-rules/wordpress/rules/gutenberg-blocks.md +493 -0
  7. package/augment-extensions/domain-rules/wordpress/rules/performance.md +568 -0
  8. package/augment-extensions/domain-rules/wordpress/rules/plugin-development.md +510 -0
  9. package/augment-extensions/domain-rules/wordpress/rules/project-detection.md +251 -0
  10. package/augment-extensions/domain-rules/wordpress/rules/rest-api.md +501 -0
  11. package/augment-extensions/domain-rules/wordpress/rules/security.md +564 -0
  12. package/augment-extensions/domain-rules/wordpress/rules/theme-development.md +388 -0
  13. package/augment-extensions/domain-rules/wordpress/rules/woocommerce.md +441 -0
  14. package/augment-extensions/domain-rules/wordpress-plugin/README.md +139 -0
  15. package/augment-extensions/domain-rules/wordpress-plugin/examples/ajax-plugin.md +1599 -0
  16. package/augment-extensions/domain-rules/wordpress-plugin/examples/custom-post-type-plugin.md +1727 -0
  17. package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block-plugin.md +428 -0
  18. package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block.md +422 -0
  19. package/augment-extensions/domain-rules/wordpress-plugin/examples/mvc-plugin.md +1623 -0
  20. package/augment-extensions/domain-rules/wordpress-plugin/examples/object-oriented-plugin.md +1343 -0
  21. package/augment-extensions/domain-rules/wordpress-plugin/examples/rest-endpoint.md +734 -0
  22. package/augment-extensions/domain-rules/wordpress-plugin/examples/settings-page-plugin.md +1350 -0
  23. package/augment-extensions/domain-rules/wordpress-plugin/examples/simple-procedural-plugin.md +503 -0
  24. package/augment-extensions/domain-rules/wordpress-plugin/examples/singleton-plugin.md +971 -0
  25. package/augment-extensions/domain-rules/wordpress-plugin/module.json +53 -0
  26. package/augment-extensions/domain-rules/wordpress-plugin/rules/activation-hooks.md +770 -0
  27. package/augment-extensions/domain-rules/wordpress-plugin/rules/admin-interface.md +874 -0
  28. package/augment-extensions/domain-rules/wordpress-plugin/rules/ajax-handlers.md +629 -0
  29. package/augment-extensions/domain-rules/wordpress-plugin/rules/asset-management.md +559 -0
  30. package/augment-extensions/domain-rules/wordpress-plugin/rules/context-providers.md +709 -0
  31. package/augment-extensions/domain-rules/wordpress-plugin/rules/cron-jobs.md +736 -0
  32. package/augment-extensions/domain-rules/wordpress-plugin/rules/database-management.md +1057 -0
  33. package/augment-extensions/domain-rules/wordpress-plugin/rules/documentation-standards.md +463 -0
  34. package/augment-extensions/domain-rules/wordpress-plugin/rules/frontend-functionality.md +478 -0
  35. package/augment-extensions/domain-rules/wordpress-plugin/rules/gutenberg-blocks.md +818 -0
  36. package/augment-extensions/domain-rules/wordpress-plugin/rules/internationalization.md +416 -0
  37. package/augment-extensions/domain-rules/wordpress-plugin/rules/migration.md +667 -0
  38. package/augment-extensions/domain-rules/wordpress-plugin/rules/performance-optimization.md +878 -0
  39. package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-architecture.md +693 -0
  40. package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-structure.md +352 -0
  41. package/augment-extensions/domain-rules/wordpress-plugin/rules/rest-api.md +818 -0
  42. package/augment-extensions/domain-rules/wordpress-plugin/rules/scaffolding-workflow.md +624 -0
  43. package/augment-extensions/domain-rules/wordpress-plugin/rules/security-best-practices.md +866 -0
  44. package/augment-extensions/domain-rules/wordpress-plugin/rules/testing-patterns.md +1165 -0
  45. package/augment-extensions/domain-rules/wordpress-plugin/rules/testing.md +414 -0
  46. package/augment-extensions/domain-rules/wordpress-plugin/rules/vscode-integration.md +751 -0
  47. package/augment-extensions/domain-rules/wordpress-plugin/rules/woocommerce-integration.md +949 -0
  48. package/augment-extensions/domain-rules/wordpress-plugin/rules/wordpress-org-submission.md +458 -0
  49. package/augment-extensions/examples/gutenberg-block-plugin/README.md +101 -0
  50. package/augment-extensions/examples/gutenberg-block-plugin/examples/testimonial-block.md +428 -0
  51. package/augment-extensions/examples/gutenberg-block-plugin/module.json +40 -0
  52. package/augment-extensions/examples/rest-api-plugin/README.md +98 -0
  53. package/augment-extensions/examples/rest-api-plugin/examples/task-manager-api.md +1299 -0
  54. package/augment-extensions/examples/rest-api-plugin/module.json +40 -0
  55. package/augment-extensions/examples/woocommerce-extension/README.md +98 -0
  56. package/augment-extensions/examples/woocommerce-extension/examples/product-customizer.md +763 -0
  57. package/augment-extensions/examples/woocommerce-extension/module.json +40 -0
  58. package/augment-extensions/workflows/wordpress-plugin/README.md +232 -0
  59. package/augment-extensions/workflows/wordpress-plugin/ai-prompts.md +839 -0
  60. package/augment-extensions/workflows/wordpress-plugin/bead-decomposition-patterns.md +854 -0
  61. package/augment-extensions/workflows/wordpress-plugin/examples/complete-plugin-example.md +540 -0
  62. package/augment-extensions/workflows/wordpress-plugin/examples/custom-post-type-example.md +1083 -0
  63. package/augment-extensions/workflows/wordpress-plugin/examples/feature-addition-workflow.md +669 -0
  64. package/augment-extensions/workflows/wordpress-plugin/examples/plugin-creation-workflow.md +597 -0
  65. package/augment-extensions/workflows/wordpress-plugin/examples/secure-form-handler-example.md +925 -0
  66. package/augment-extensions/workflows/wordpress-plugin/examples/security-audit-workflow.md +752 -0
  67. package/augment-extensions/workflows/wordpress-plugin/examples/wordpress-org-submission-workflow.md +773 -0
  68. package/augment-extensions/workflows/wordpress-plugin/module.json +49 -0
  69. package/augment-extensions/workflows/wordpress-plugin/rules/best-practices.md +942 -0
  70. package/augment-extensions/workflows/wordpress-plugin/rules/development-workflow.md +702 -0
  71. package/augment-extensions/workflows/wordpress-plugin/rules/submission-workflow.md +728 -0
  72. package/augment-extensions/workflows/wordpress-plugin/rules/testing-workflow.md +775 -0
  73. package/cli/dist/cli.js +5 -1
  74. package/cli/dist/cli.js.map +1 -1
  75. package/cli/dist/commands/show.d.ts.map +1 -1
  76. package/cli/dist/commands/show.js +41 -0
  77. package/cli/dist/commands/show.js.map +1 -1
  78. package/modules.md +52 -0
  79. package/package.json +1 -1
@@ -0,0 +1,874 @@
1
+ # WordPress Plugin Admin Interface
2
+
3
+ ## Overview
4
+
5
+ This document covers creating admin interfaces for WordPress plugins, including settings pages, meta boxes, admin notices, list tables, and dashboard widgets.
6
+
7
+ ---
8
+
9
+ ## Settings Pages
10
+
11
+ ### Adding a Top-Level Menu
12
+
13
+ ```php
14
+ <?php
15
+ add_action('admin_menu', 'my_plugin_add_admin_menu');
16
+
17
+ function my_plugin_add_admin_menu() {
18
+ add_menu_page(
19
+ 'My Plugin Settings', // Page title
20
+ 'My Plugin', // Menu title
21
+ 'manage_options', // Capability
22
+ 'my-plugin', // Menu slug
23
+ 'my_plugin_settings_page', // Callback function
24
+ 'dashicons-admin-generic', // Icon
25
+ 20 // Position
26
+ );
27
+ }
28
+
29
+ function my_plugin_settings_page() {
30
+ // Check user capabilities
31
+ if (!current_user_can('manage_options')) {
32
+ return;
33
+ }
34
+
35
+ ?>
36
+ <div class="wrap">
37
+ <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
38
+ <form action="options.php" method="post">
39
+ <?php
40
+ settings_fields('my_plugin_options');
41
+ do_settings_sections('my-plugin');
42
+ submit_button('Save Settings');
43
+ ?>
44
+ </form>
45
+ </div>
46
+ <?php
47
+ }
48
+ ```
49
+
50
+ ### Adding a Submenu Page
51
+
52
+ ```php
53
+ <?php
54
+ add_action('admin_menu', 'my_plugin_add_submenu');
55
+
56
+ function my_plugin_add_submenu() {
57
+ // Add to Settings menu
58
+ add_options_page(
59
+ 'My Plugin Settings', // Page title
60
+ 'My Plugin', // Menu title
61
+ 'manage_options', // Capability
62
+ 'my-plugin', // Menu slug
63
+ 'my_plugin_settings_page' // Callback
64
+ );
65
+
66
+ // Or add to Tools menu
67
+ add_management_page(
68
+ 'My Plugin Tools',
69
+ 'My Plugin',
70
+ 'manage_options',
71
+ 'my-plugin-tools',
72
+ 'my_plugin_tools_page'
73
+ );
74
+ }
75
+ ```
76
+
77
+ ### Settings API Implementation
78
+
79
+ ```php
80
+ <?php
81
+ add_action('admin_init', 'my_plugin_settings_init');
82
+
83
+ function my_plugin_settings_init() {
84
+ // Register setting
85
+ register_setting(
86
+ 'my_plugin_options', // Option group
87
+ 'my_plugin_settings', // Option name
88
+ 'my_plugin_sanitize_settings' // Sanitize callback
89
+ );
90
+
91
+ // Add settings section
92
+ add_settings_section(
93
+ 'my_plugin_section_general', // Section ID
94
+ 'General Settings', // Title
95
+ 'my_plugin_section_callback', // Callback
96
+ 'my-plugin' // Page slug
97
+ );
98
+
99
+ // Add settings fields
100
+ add_settings_field(
101
+ 'my_plugin_field_api_key', // Field ID
102
+ 'API Key', // Title
103
+ 'my_plugin_field_api_key_cb', // Callback
104
+ 'my-plugin', // Page slug
105
+ 'my_plugin_section_general', // Section ID
106
+ array(
107
+ 'label_for' => 'api_key',
108
+ 'class' => 'my_plugin_row'
109
+ )
110
+ );
111
+
112
+ add_settings_field(
113
+ 'my_plugin_field_enabled',
114
+ 'Enable Feature',
115
+ 'my_plugin_field_enabled_cb',
116
+ 'my-plugin',
117
+ 'my_plugin_section_general',
118
+ array('label_for' => 'enabled')
119
+ );
120
+ }
121
+
122
+ function my_plugin_section_callback($args) {
123
+ ?>
124
+ <p>Configure your plugin settings below.</p>
125
+ <?php
126
+ }
127
+
128
+ function my_plugin_field_api_key_cb($args) {
129
+ $options = get_option('my_plugin_settings');
130
+ $value = isset($options['api_key']) ? $options['api_key'] : '';
131
+ ?>
132
+ <input
133
+ type="text"
134
+ id="<?php echo esc_attr($args['label_for']); ?>"
135
+ name="my_plugin_settings[<?php echo esc_attr($args['label_for']); ?>]"
136
+ value="<?php echo esc_attr($value); ?>"
137
+ class="regular-text"
138
+ />
139
+ <p class="description">Enter your API key from the provider.</p>
140
+ <?php
141
+ }
142
+
143
+ function my_plugin_field_enabled_cb($args) {
144
+ $options = get_option('my_plugin_settings');
145
+ $checked = isset($options['enabled']) ? $options['enabled'] : false;
146
+ ?>
147
+ <input
148
+ type="checkbox"
149
+ id="<?php echo esc_attr($args['label_for']); ?>"
150
+ name="my_plugin_settings[<?php echo esc_attr($args['label_for']); ?>]"
151
+ value="1"
152
+ <?php checked($checked, 1); ?>
153
+ />
154
+ <label for="<?php echo esc_attr($args['label_for']); ?>">
155
+ Enable this feature
156
+ </label>
157
+ <?php
158
+ }
159
+
160
+ function my_plugin_sanitize_settings($input) {
161
+ $sanitized = array();
162
+
163
+ // Sanitize API key
164
+ if (isset($input['api_key'])) {
165
+ $sanitized['api_key'] = sanitize_text_field($input['api_key']);
166
+ }
167
+
168
+ // Sanitize checkbox
169
+ $sanitized['enabled'] = isset($input['enabled']) ? 1 : 0;
170
+
171
+ return $sanitized;
172
+ }
173
+ ```
174
+
175
+ ### Object-Oriented Settings Page
176
+
177
+ ```php
178
+ <?php
179
+ class My_Plugin_Admin {
180
+ private $plugin_name;
181
+ private $version;
182
+
183
+ public function __construct($plugin_name, $version) {
184
+ $this->plugin_name = $plugin_name;
185
+ $this->version = $version;
186
+ }
187
+
188
+ public function add_admin_menu() {
189
+ add_menu_page(
190
+ 'My Plugin',
191
+ 'My Plugin',
192
+ 'manage_options',
193
+ $this->plugin_name,
194
+ array($this, 'display_settings_page'),
195
+ 'dashicons-admin-generic'
196
+ );
197
+ }
198
+
199
+ public function register_settings() {
200
+ register_setting(
201
+ $this->plugin_name . '_options',
202
+ $this->plugin_name . '_settings',
203
+ array($this, 'sanitize_settings')
204
+ );
205
+
206
+ add_settings_section(
207
+ $this->plugin_name . '_section',
208
+ 'General Settings',
209
+ array($this, 'section_callback'),
210
+ $this->plugin_name
211
+ );
212
+
213
+ add_settings_field(
214
+ 'api_key',
215
+ 'API Key',
216
+ array($this, 'api_key_field'),
217
+ $this->plugin_name,
218
+ $this->plugin_name . '_section'
219
+ );
220
+ }
221
+
222
+ public function display_settings_page() {
223
+ if (!current_user_can('manage_options')) {
224
+ return;
225
+ }
226
+
227
+ include_once plugin_dir_path(__FILE__) . 'partials/admin-display.php';
228
+ }
229
+
230
+ public function section_callback() {
231
+ echo '<p>Configure your plugin settings.</p>';
232
+ }
233
+
234
+ public function api_key_field() {
235
+ $options = get_option($this->plugin_name . '_settings');
236
+ $value = isset($options['api_key']) ? $options['api_key'] : '';
237
+
238
+ printf(
239
+ '<input type="text" name="%s[api_key]" value="%s" class="regular-text" />',
240
+ esc_attr($this->plugin_name . '_settings'),
241
+ esc_attr($value)
242
+ );
243
+ }
244
+
245
+ public function sanitize_settings($input) {
246
+ $sanitized = array();
247
+
248
+ if (isset($input['api_key'])) {
249
+ $sanitized['api_key'] = sanitize_text_field($input['api_key']);
250
+ }
251
+
252
+ return $sanitized;
253
+ }
254
+ }
255
+
256
+ // Hook it up
257
+ $admin = new My_Plugin_Admin('my-plugin', '1.0.0');
258
+ add_action('admin_menu', array($admin, 'add_admin_menu'));
259
+ add_action('admin_init', array($admin, 'register_settings'));
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Meta Boxes
265
+
266
+ ### Adding a Meta Box
267
+
268
+ ```php
269
+ <?php
270
+ add_action('add_meta_boxes', 'my_plugin_add_meta_box');
271
+
272
+ function my_plugin_add_meta_box() {
273
+ add_meta_box(
274
+ 'my_plugin_meta_box', // Meta box ID
275
+ 'My Plugin Settings', // Title
276
+ 'my_plugin_meta_box_callback', // Callback
277
+ 'post', // Post type (or array of post types)
278
+ 'side', // Context (normal, side, advanced)
279
+ 'default' // Priority (high, default, low)
280
+ );
281
+ }
282
+
283
+ function my_plugin_meta_box_callback($post) {
284
+ // Add nonce for security
285
+ wp_nonce_field('my_plugin_save_meta_box', 'my_plugin_meta_box_nonce');
286
+
287
+ // Get current value
288
+ $value = get_post_meta($post->ID, '_my_plugin_field', true);
289
+
290
+ ?>
291
+ <label for="my_plugin_field">Custom Field:</label>
292
+ <input
293
+ type="text"
294
+ id="my_plugin_field"
295
+ name="my_plugin_field"
296
+ value="<?php echo esc_attr($value); ?>"
297
+ class="widefat"
298
+ />
299
+ <?php
300
+ }
301
+
302
+ // Save meta box data
303
+ add_action('save_post', 'my_plugin_save_meta_box');
304
+
305
+ function my_plugin_save_meta_box($post_id) {
306
+ // Check nonce
307
+ if (!isset($_POST['my_plugin_meta_box_nonce'])) {
308
+ return;
309
+ }
310
+
311
+ if (!wp_verify_nonce($_POST['my_plugin_meta_box_nonce'], 'my_plugin_save_meta_box')) {
312
+ return;
313
+ }
314
+
315
+ // Check autosave
316
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
317
+ return;
318
+ }
319
+
320
+ // Check permissions
321
+ if (!current_user_can('edit_post', $post_id)) {
322
+ return;
323
+ }
324
+
325
+ // Sanitize and save
326
+ if (isset($_POST['my_plugin_field'])) {
327
+ $value = sanitize_text_field($_POST['my_plugin_field']);
328
+ update_post_meta($post_id, '_my_plugin_field', $value);
329
+ }
330
+ }
331
+ ```
332
+
333
+ ### Object-Oriented Meta Box
334
+
335
+ ```php
336
+ <?php
337
+ class My_Plugin_Meta_Box {
338
+ public function __construct() {
339
+ add_action('add_meta_boxes', array($this, 'add_meta_box'));
340
+ add_action('save_post', array($this, 'save_meta_box'));
341
+ }
342
+
343
+ public function add_meta_box() {
344
+ $post_types = array('post', 'page', 'custom_post_type');
345
+
346
+ foreach ($post_types as $post_type) {
347
+ add_meta_box(
348
+ 'my_plugin_meta_box',
349
+ 'My Plugin Settings',
350
+ array($this, 'render_meta_box'),
351
+ $post_type,
352
+ 'normal',
353
+ 'high'
354
+ );
355
+ }
356
+ }
357
+
358
+ public function render_meta_box($post) {
359
+ wp_nonce_field('my_plugin_meta_box', 'my_plugin_meta_box_nonce');
360
+
361
+ $project_url = get_post_meta($post->ID, '_project_url', true);
362
+ $project_date = get_post_meta($post->ID, '_project_date', true);
363
+
364
+ ?>
365
+ <table class="form-table">
366
+ <tr>
367
+ <th><label for="project_url">Project URL</label></th>
368
+ <td>
369
+ <input
370
+ type="url"
371
+ id="project_url"
372
+ name="project_url"
373
+ value="<?php echo esc_url($project_url); ?>"
374
+ class="regular-text"
375
+ />
376
+ </td>
377
+ </tr>
378
+ <tr>
379
+ <th><label for="project_date">Project Date</label></th>
380
+ <td>
381
+ <input
382
+ type="date"
383
+ id="project_date"
384
+ name="project_date"
385
+ value="<?php echo esc_attr($project_date); ?>"
386
+ />
387
+ </td>
388
+ </tr>
389
+ </table>
390
+ <?php
391
+ }
392
+
393
+ public function save_meta_box($post_id) {
394
+ // Verify nonce
395
+ if (!isset($_POST['my_plugin_meta_box_nonce'])) {
396
+ return;
397
+ }
398
+
399
+ if (!wp_verify_nonce($_POST['my_plugin_meta_box_nonce'], 'my_plugin_meta_box')) {
400
+ return;
401
+ }
402
+
403
+ // Check autosave
404
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
405
+ return;
406
+ }
407
+
408
+ // Check permissions
409
+ if (!current_user_can('edit_post', $post_id)) {
410
+ return;
411
+ }
412
+
413
+ // Save project URL
414
+ if (isset($_POST['project_url'])) {
415
+ update_post_meta(
416
+ $post_id,
417
+ '_project_url',
418
+ esc_url_raw($_POST['project_url'])
419
+ );
420
+ }
421
+
422
+ // Save project date
423
+ if (isset($_POST['project_date'])) {
424
+ update_post_meta(
425
+ $post_id,
426
+ '_project_date',
427
+ sanitize_text_field($_POST['project_date'])
428
+ );
429
+ }
430
+ }
431
+ }
432
+
433
+ new My_Plugin_Meta_Box();
434
+ ```
435
+
436
+ ---
437
+
438
+ ## Admin Notices
439
+
440
+ ### Basic Admin Notice
441
+
442
+ ```php
443
+ <?php
444
+ add_action('admin_notices', 'my_plugin_admin_notice');
445
+
446
+ function my_plugin_admin_notice() {
447
+ ?>
448
+ <div class="notice notice-success is-dismissible">
449
+ <p>Settings saved successfully!</p>
450
+ </div>
451
+ <?php
452
+ }
453
+ ```
454
+
455
+ ### Notice Types
456
+
457
+ ```php
458
+ <?php
459
+ function my_plugin_show_notices() {
460
+ // Success notice
461
+ ?>
462
+ <div class="notice notice-success is-dismissible">
463
+ <p>Success message</p>
464
+ </div>
465
+
466
+ <!-- Error notice -->
467
+ <div class="notice notice-error">
468
+ <p>Error message</p>
469
+ </div>
470
+
471
+ <!-- Warning notice -->
472
+ <div class="notice notice-warning">
473
+ <p>Warning message</p>
474
+ </div>
475
+
476
+ <!-- Info notice -->
477
+ <div class="notice notice-info">
478
+ <p>Info message</p>
479
+ </div>
480
+ <?php
481
+ }
482
+ ```
483
+
484
+ ### Conditional Admin Notices
485
+
486
+ ```php
487
+ <?php
488
+ add_action('admin_notices', 'my_plugin_conditional_notice');
489
+
490
+ function my_plugin_conditional_notice() {
491
+ // Only show on plugin settings page
492
+ $screen = get_current_screen();
493
+ if ($screen->id !== 'toplevel_page_my-plugin') {
494
+ return;
495
+ }
496
+
497
+ // Check if settings are configured
498
+ $settings = get_option('my_plugin_settings');
499
+ if (empty($settings['api_key'])) {
500
+ ?>
501
+ <div class="notice notice-warning">
502
+ <p>
503
+ <strong>My Plugin:</strong>
504
+ Please configure your API key in
505
+ <a href="<?php echo admin_url('admin.php?page=my-plugin'); ?>">settings</a>.
506
+ </p>
507
+ </div>
508
+ <?php
509
+ }
510
+ }
511
+ ```
512
+
513
+ ### Dismissible Notices with Transients
514
+
515
+ ```php
516
+ <?php
517
+ add_action('admin_notices', 'my_plugin_dismissible_notice');
518
+
519
+ function my_plugin_dismissible_notice() {
520
+ // Check if notice was dismissed
521
+ if (get_transient('my_plugin_notice_dismissed')) {
522
+ return;
523
+ }
524
+
525
+ ?>
526
+ <div class="notice notice-info is-dismissible" data-notice="my-plugin-welcome">
527
+ <p>Welcome to My Plugin! <a href="#">Get started</a></p>
528
+ </div>
529
+
530
+ <script>
531
+ jQuery(document).ready(function($) {
532
+ $(document).on('click', '.notice[data-notice="my-plugin-welcome"] .notice-dismiss', function() {
533
+ $.post(ajaxurl, {
534
+ action: 'my_plugin_dismiss_notice',
535
+ nonce: '<?php echo wp_create_nonce('my_plugin_dismiss_notice'); ?>'
536
+ });
537
+ });
538
+ });
539
+ </script>
540
+ <?php
541
+ }
542
+
543
+ // Handle AJAX dismiss
544
+ add_action('wp_ajax_my_plugin_dismiss_notice', 'my_plugin_handle_dismiss_notice');
545
+
546
+ function my_plugin_handle_dismiss_notice() {
547
+ check_ajax_referer('my_plugin_dismiss_notice', 'nonce');
548
+
549
+ set_transient('my_plugin_notice_dismissed', true, WEEK_IN_SECONDS);
550
+
551
+ wp_send_json_success();
552
+ }
553
+ ```
554
+
555
+ ---
556
+
557
+ ## List Tables
558
+
559
+ ### Custom List Table
560
+
561
+ ```php
562
+ <?php
563
+ if (!class_exists('WP_List_Table')) {
564
+ require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
565
+ }
566
+
567
+ class My_Plugin_List_Table extends WP_List_Table {
568
+ public function __construct() {
569
+ parent::__construct(array(
570
+ 'singular' => 'item',
571
+ 'plural' => 'items',
572
+ 'ajax' => false
573
+ ));
574
+ }
575
+
576
+ public function get_columns() {
577
+ return array(
578
+ 'cb' => '<input type="checkbox" />',
579
+ 'title' => 'Title',
580
+ 'author' => 'Author',
581
+ 'date' => 'Date',
582
+ 'status' => 'Status'
583
+ );
584
+ }
585
+
586
+ public function get_sortable_columns() {
587
+ return array(
588
+ 'title' => array('title', false),
589
+ 'date' => array('date', true)
590
+ );
591
+ }
592
+
593
+ public function column_default($item, $column_name) {
594
+ switch ($column_name) {
595
+ case 'title':
596
+ case 'author':
597
+ case 'date':
598
+ case 'status':
599
+ return $item[$column_name];
600
+ default:
601
+ return print_r($item, true);
602
+ }
603
+ }
604
+
605
+ public function column_cb($item) {
606
+ return sprintf(
607
+ '<input type="checkbox" name="items[]" value="%s" />',
608
+ $item['id']
609
+ );
610
+ }
611
+
612
+ public function column_title($item) {
613
+ $actions = array(
614
+ 'edit' => sprintf(
615
+ '<a href="?page=%s&action=edit&item=%s">Edit</a>',
616
+ $_REQUEST['page'],
617
+ $item['id']
618
+ ),
619
+ 'delete' => sprintf(
620
+ '<a href="?page=%s&action=delete&item=%s">Delete</a>',
621
+ $_REQUEST['page'],
622
+ $item['id']
623
+ )
624
+ );
625
+
626
+ return sprintf(
627
+ '%1$s %2$s',
628
+ $item['title'],
629
+ $this->row_actions($actions)
630
+ );
631
+ }
632
+
633
+ public function get_bulk_actions() {
634
+ return array(
635
+ 'delete' => 'Delete',
636
+ 'export' => 'Export'
637
+ );
638
+ }
639
+
640
+ public function prepare_items() {
641
+ $columns = $this->get_columns();
642
+ $hidden = array();
643
+ $sortable = $this->get_sortable_columns();
644
+
645
+ $this->_column_headers = array($columns, $hidden, $sortable);
646
+
647
+ // Get data
648
+ $data = $this->get_data();
649
+
650
+ // Pagination
651
+ $per_page = 20;
652
+ $current_page = $this->get_pagenum();
653
+ $total_items = count($data);
654
+
655
+ $this->set_pagination_args(array(
656
+ 'total_items' => $total_items,
657
+ 'per_page' => $per_page,
658
+ 'total_pages' => ceil($total_items / $per_page)
659
+ ));
660
+
661
+ $this->items = array_slice($data, (($current_page - 1) * $per_page), $per_page);
662
+ }
663
+
664
+ private function get_data() {
665
+ // Get data from database
666
+ global $wpdb;
667
+ $table_name = $wpdb->prefix . 'my_plugin_data';
668
+
669
+ return $wpdb->get_results(
670
+ "SELECT * FROM $table_name ORDER BY date DESC",
671
+ ARRAY_A
672
+ );
673
+ }
674
+ }
675
+
676
+ // Display list table
677
+ function my_plugin_list_page() {
678
+ $list_table = new My_Plugin_List_Table();
679
+ $list_table->prepare_items();
680
+
681
+ ?>
682
+ <div class="wrap">
683
+ <h1>My Plugin Items</h1>
684
+ <form method="post">
685
+ <?php $list_table->display(); ?>
686
+ </form>
687
+ </div>
688
+ <?php
689
+ }
690
+ ```
691
+
692
+ ---
693
+
694
+ ## Dashboard Widgets
695
+
696
+ ### Adding a Dashboard Widget
697
+
698
+ ```php
699
+ <?php
700
+ add_action('wp_dashboard_setup', 'my_plugin_add_dashboard_widget');
701
+
702
+ function my_plugin_add_dashboard_widget() {
703
+ wp_add_dashboard_widget(
704
+ 'my_plugin_dashboard_widget', // Widget ID
705
+ 'My Plugin Stats', // Title
706
+ 'my_plugin_dashboard_widget_render' // Callback
707
+ );
708
+ }
709
+
710
+ function my_plugin_dashboard_widget_render() {
711
+ // Get stats
712
+ $total_items = wp_count_posts('my_custom_post_type')->publish;
713
+ $recent_items = get_posts(array(
714
+ 'post_type' => 'my_custom_post_type',
715
+ 'posts_per_page' => 5
716
+ ));
717
+
718
+ ?>
719
+ <div class="my-plugin-dashboard-widget">
720
+ <p><strong>Total Items:</strong> <?php echo esc_html($total_items); ?></p>
721
+
722
+ <h4>Recent Items</h4>
723
+ <ul>
724
+ <?php foreach ($recent_items as $item) : ?>
725
+ <li>
726
+ <a href="<?php echo get_edit_post_link($item->ID); ?>">
727
+ <?php echo esc_html($item->post_title); ?>
728
+ </a>
729
+ </li>
730
+ <?php endforeach; ?>
731
+ </ul>
732
+ </div>
733
+ <?php
734
+ }
735
+ ```
736
+
737
+ ---
738
+
739
+ ## Admin Columns
740
+
741
+ ### Adding Custom Columns to Post List
742
+
743
+ ```php
744
+ <?php
745
+ // Add column
746
+ add_filter('manage_post_posts_columns', 'my_plugin_add_custom_column');
747
+
748
+ function my_plugin_add_custom_column($columns) {
749
+ $columns['my_custom_field'] = 'Custom Field';
750
+ return $columns;
751
+ }
752
+
753
+ // Populate column
754
+ add_action('manage_post_posts_custom_column', 'my_plugin_populate_custom_column', 10, 2);
755
+
756
+ function my_plugin_populate_custom_column($column, $post_id) {
757
+ if ($column === 'my_custom_field') {
758
+ $value = get_post_meta($post_id, '_my_custom_field', true);
759
+ echo esc_html($value);
760
+ }
761
+ }
762
+
763
+ // Make column sortable
764
+ add_filter('manage_edit-post_sortable_columns', 'my_plugin_sortable_column');
765
+
766
+ function my_plugin_sortable_column($columns) {
767
+ $columns['my_custom_field'] = 'my_custom_field';
768
+ return $columns;
769
+ }
770
+ ```
771
+
772
+ ---
773
+
774
+ ## Best Practices
775
+
776
+ ### Settings Pages
777
+
778
+ ✅ Check user capabilities (`current_user_can()`)
779
+ ✅ Use Settings API for options
780
+ ✅ Sanitize all input
781
+ ✅ Use nonces for form submissions
782
+ ✅ Provide helpful descriptions
783
+ ✅ Group related settings
784
+ ✅ Use appropriate input types
785
+
786
+ ### Meta Boxes
787
+
788
+ ✅ Always use nonces
789
+ ✅ Check autosave
790
+ ✅ Verify user permissions
791
+ ✅ Sanitize input based on type
792
+ ✅ Use `update_post_meta()` not direct DB queries
793
+ ✅ Prefix meta keys with underscore for private fields
794
+
795
+ ### Admin Notices
796
+
797
+ ✅ Use appropriate notice types
798
+ ✅ Make notices dismissible when appropriate
799
+ ✅ Show notices only on relevant pages
800
+ ✅ Provide actionable information
801
+ ✅ Don't overwhelm users with notices
802
+
803
+ ### Security
804
+
805
+ ✅ Always check capabilities
806
+ ✅ Use nonces for all forms
807
+ ✅ Sanitize input, escape output
808
+ ✅ Use `wp_verify_nonce()` before processing
809
+ ✅ Check `DOING_AUTOSAVE` in save hooks
810
+ ✅ Validate data types
811
+
812
+ ---
813
+
814
+ ## Common Patterns
815
+
816
+ ### Tabbed Settings Page
817
+
818
+ ```php
819
+ <?php
820
+ function my_plugin_settings_page() {
821
+ $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
822
+
823
+ ?>
824
+ <div class="wrap">
825
+ <h1>My Plugin Settings</h1>
826
+
827
+ <h2 class="nav-tab-wrapper">
828
+ <a href="?page=my-plugin&tab=general" class="nav-tab <?php echo $active_tab == 'general' ? 'nav-tab-active' : ''; ?>">
829
+ General
830
+ </a>
831
+ <a href="?page=my-plugin&tab=advanced" class="nav-tab <?php echo $active_tab == 'advanced' ? 'nav-tab-active' : ''; ?>">
832
+ Advanced
833
+ </a>
834
+ <a href="?page=my-plugin&tab=help" class="nav-tab <?php echo $active_tab == 'help' ? 'nav-tab-active' : ''; ?>">
835
+ Help
836
+ </a>
837
+ </h2>
838
+
839
+ <form method="post" action="options.php">
840
+ <?php
841
+ if ($active_tab == 'general') {
842
+ settings_fields('my_plugin_general');
843
+ do_settings_sections('my-plugin-general');
844
+ } elseif ($active_tab == 'advanced') {
845
+ settings_fields('my_plugin_advanced');
846
+ do_settings_sections('my-plugin-advanced');
847
+ } else {
848
+ // Help tab content
849
+ echo '<p>Help content here</p>';
850
+ }
851
+
852
+ if ($active_tab != 'help') {
853
+ submit_button();
854
+ }
855
+ ?>
856
+ </form>
857
+ </div>
858
+ <?php
859
+ }
860
+ ```
861
+
862
+ ---
863
+
864
+ ## Summary
865
+
866
+ | Component | Purpose | Key Functions |
867
+ |-----------|---------|---------------|
868
+ | Settings Pages | Plugin configuration | `add_menu_page()`, `register_setting()` |
869
+ | Meta Boxes | Post/page custom fields | `add_meta_box()`, `update_post_meta()` |
870
+ | Admin Notices | User notifications | `admin_notices` hook |
871
+ | List Tables | Custom data tables | `WP_List_Table` class |
872
+ | Dashboard Widgets | Dashboard info | `wp_add_dashboard_widget()` |
873
+ | Admin Columns | Custom list columns | `manage_{post_type}_posts_columns` |
874
+