@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,1083 @@
1
+ # Custom Post Type Example
2
+
3
+ This example demonstrates creating a custom post type with taxonomy, meta boxes, and frontend display in a WordPress plugin.
4
+
5
+ ## Scenario
6
+
7
+ Creating a "Book Review" custom post type for a WordPress plugin that allows users to manage and display book reviews.
8
+
9
+ ## Plugin Context
10
+
11
+ **Plugin**: Book Reviews
12
+ **Feature**: Custom post type for book reviews with rating, author, and genre
13
+ **Custom Post Type**: `book_review`
14
+ **Custom Taxonomy**: `book_genre`
15
+
16
+ ## Complete Implementation
17
+
18
+ ### Main Plugin File
19
+
20
+ **File**: `book-reviews.php`
21
+
22
+ ```php
23
+ <?php
24
+ /**
25
+ * Plugin Name: Book Reviews
26
+ * Plugin URI: https://example.com/book-reviews
27
+ * Description: Manage and display book reviews with ratings and genres
28
+ * Version: 1.0.0
29
+ * Author: Your Name
30
+ * Author URI: https://example.com
31
+ * License: GPL-2.0+
32
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
33
+ * Text Domain: book-reviews
34
+ * Domain Path: /languages
35
+ */
36
+
37
+ // If this file is called directly, abort.
38
+ if (!defined('WPINC')) {
39
+ die;
40
+ }
41
+
42
+ define('BOOK_REVIEWS_VERSION', '1.0.0');
43
+ define('BOOK_REVIEWS_PLUGIN_DIR', plugin_dir_path(__FILE__));
44
+ define('BOOK_REVIEWS_PLUGIN_URL', plugin_dir_url(__FILE__));
45
+
46
+ /**
47
+ * The code that runs during plugin activation.
48
+ */
49
+ function activate_book_reviews() {
50
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-reviews-activator.php';
51
+ Book_Reviews_Activator::activate();
52
+ }
53
+
54
+ /**
55
+ * The code that runs during plugin deactivation.
56
+ */
57
+ function deactivate_book_reviews() {
58
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-reviews-deactivator.php';
59
+ Book_Reviews_Deactivator::deactivate();
60
+ }
61
+
62
+ register_activation_hook(__FILE__, 'activate_book_reviews');
63
+ register_deactivation_hook(__FILE__, 'deactivate_book_reviews');
64
+
65
+ /**
66
+ * The core plugin class.
67
+ */
68
+ require BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-reviews.php';
69
+
70
+ /**
71
+ * Begins execution of the plugin.
72
+ */
73
+ function run_book_reviews() {
74
+ $plugin = new Book_Reviews();
75
+ $plugin->run();
76
+ }
77
+ run_book_reviews();
78
+ ```
79
+
80
+ ### Activator Class
81
+
82
+ **File**: `includes/class-book-reviews-activator.php`
83
+
84
+ ```php
85
+ <?php
86
+ /**
87
+ * Fired during plugin activation.
88
+ */
89
+ class Book_Reviews_Activator {
90
+
91
+ /**
92
+ * Activate the plugin.
93
+ */
94
+ public static function activate() {
95
+ // Register post type and taxonomy
96
+ self::register_post_type();
97
+ self::register_taxonomy();
98
+
99
+ // Flush rewrite rules
100
+ flush_rewrite_rules();
101
+ }
102
+
103
+ /**
104
+ * Register the custom post type.
105
+ */
106
+ private static function register_post_type() {
107
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-review-post-type.php';
108
+ $post_type = new Book_Review_Post_Type();
109
+ $post_type->register();
110
+ }
111
+
112
+ /**
113
+ * Register the custom taxonomy.
114
+ */
115
+ private static function register_taxonomy() {
116
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-genre-taxonomy.php';
117
+ $taxonomy = new Book_Genre_Taxonomy();
118
+ $taxonomy->register();
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### Deactivator Class
124
+
125
+ **File**: `includes/class-book-reviews-deactivator.php`
126
+
127
+ ```php
128
+ <?php
129
+ /**
130
+ * Fired during plugin deactivation.
131
+ */
132
+ class Book_Reviews_Deactivator {
133
+
134
+ /**
135
+ * Deactivate the plugin.
136
+ */
137
+ public static function deactivate() {
138
+ // Flush rewrite rules
139
+ flush_rewrite_rules();
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### Core Plugin Class
145
+
146
+ **File**: `includes/class-book-reviews.php`
147
+
148
+ ```php
149
+ <?php
150
+ /**
151
+ * The core plugin class.
152
+ */
153
+ class Book_Reviews {
154
+
155
+ /**
156
+ * The loader that's responsible for maintaining and registering all hooks.
157
+ */
158
+ protected $loader;
159
+
160
+ /**
161
+ * The unique identifier of this plugin.
162
+ */
163
+ protected $plugin_name;
164
+
165
+ /**
166
+ * The current version of the plugin.
167
+ */
168
+ protected $version;
169
+
170
+ /**
171
+ * Define the core functionality of the plugin.
172
+ */
173
+ public function __construct() {
174
+ $this->version = BOOK_REVIEWS_VERSION;
175
+ $this->plugin_name = 'book-reviews';
176
+
177
+ $this->load_dependencies();
178
+ $this->define_admin_hooks();
179
+ $this->define_public_hooks();
180
+ }
181
+
182
+ /**
183
+ * Load the required dependencies for this plugin.
184
+ */
185
+ private function load_dependencies() {
186
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-reviews-loader.php';
187
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-review-post-type.php';
188
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'includes/class-book-genre-taxonomy.php';
189
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'admin/class-book-reviews-admin.php';
190
+ require_once BOOK_REVIEWS_PLUGIN_DIR . 'public/class-book-reviews-public.php';
191
+
192
+ $this->loader = new Book_Reviews_Loader();
193
+ }
194
+
195
+ /**
196
+ * Register all of the hooks related to the admin area functionality.
197
+ */
198
+ private function define_admin_hooks() {
199
+ $admin = new Book_Reviews_Admin($this->get_plugin_name(), $this->get_version());
200
+
201
+ $this->loader->add_action('admin_enqueue_scripts', $admin, 'enqueue_styles');
202
+ $this->loader->add_action('admin_enqueue_scripts', $admin, 'enqueue_scripts');
203
+ }
204
+
205
+ /**
206
+ * Register all of the hooks related to the public-facing functionality.
207
+ */
208
+ private function define_public_hooks() {
209
+ $public = new Book_Reviews_Public($this->get_plugin_name(), $this->get_version());
210
+
211
+ $this->loader->add_action('wp_enqueue_scripts', $public, 'enqueue_styles');
212
+ $this->loader->add_action('wp_enqueue_scripts', $public, 'enqueue_scripts');
213
+
214
+ // Register post type and taxonomy
215
+ $post_type = new Book_Review_Post_Type();
216
+ $this->loader->add_action('init', $post_type, 'register');
217
+
218
+ $taxonomy = new Book_Genre_Taxonomy();
219
+ $this->loader->add_action('init', $taxonomy, 'register');
220
+ }
221
+
222
+ /**
223
+ * Run the loader to execute all of the hooks with WordPress.
224
+ */
225
+ public function run() {
226
+ $this->loader->run();
227
+ }
228
+
229
+ /**
230
+ * The name of the plugin used to uniquely identify it.
231
+ */
232
+ public function get_plugin_name() {
233
+ return $this->plugin_name;
234
+ }
235
+
236
+ /**
237
+ * Retrieve the version number of the plugin.
238
+ */
239
+ public function get_version() {
240
+ return $this->version;
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### Custom Post Type Class
246
+
247
+ **File**: `includes/class-book-review-post-type.php`
248
+
249
+ ```php
250
+ <?php
251
+ /**
252
+ * Register the Book Review custom post type.
253
+ */
254
+ class Book_Review_Post_Type {
255
+
256
+ /**
257
+ * Register the custom post type.
258
+ */
259
+ public function register() {
260
+ $labels = array(
261
+ 'name' => _x('Book Reviews', 'Post Type General Name', 'book-reviews'),
262
+ 'singular_name' => _x('Book Review', 'Post Type Singular Name', 'book-reviews'),
263
+ 'menu_name' => __('Book Reviews', 'book-reviews'),
264
+ 'name_admin_bar' => __('Book Review', 'book-reviews'),
265
+ 'archives' => __('Book Review Archives', 'book-reviews'),
266
+ 'attributes' => __('Book Review Attributes', 'book-reviews'),
267
+ 'parent_item_colon' => __('Parent Book Review:', 'book-reviews'),
268
+ 'all_items' => __('All Book Reviews', 'book-reviews'),
269
+ 'add_new_item' => __('Add New Book Review', 'book-reviews'),
270
+ 'add_new' => __('Add New', 'book-reviews'),
271
+ 'new_item' => __('New Book Review', 'book-reviews'),
272
+ 'edit_item' => __('Edit Book Review', 'book-reviews'),
273
+ 'update_item' => __('Update Book Review', 'book-reviews'),
274
+ 'view_item' => __('View Book Review', 'book-reviews'),
275
+ 'view_items' => __('View Book Reviews', 'book-reviews'),
276
+ 'search_items' => __('Search Book Review', 'book-reviews'),
277
+ 'not_found' => __('Not found', 'book-reviews'),
278
+ 'not_found_in_trash' => __('Not found in Trash', 'book-reviews'),
279
+ 'featured_image' => __('Book Cover Image', 'book-reviews'),
280
+ 'set_featured_image' => __('Set book cover image', 'book-reviews'),
281
+ 'remove_featured_image' => __('Remove book cover image', 'book-reviews'),
282
+ 'use_featured_image' => __('Use as book cover image', 'book-reviews'),
283
+ 'insert_into_item' => __('Insert into book review', 'book-reviews'),
284
+ 'uploaded_to_this_item' => __('Uploaded to this book review', 'book-reviews'),
285
+ 'items_list' => __('Book Reviews list', 'book-reviews'),
286
+ 'items_list_navigation' => __('Book Reviews list navigation', 'book-reviews'),
287
+ 'filter_items_list' => __('Filter book reviews list', 'book-reviews'),
288
+ );
289
+
290
+ $args = array(
291
+ 'label' => __('Book Review', 'book-reviews'),
292
+ 'description' => __('Book reviews with ratings and metadata', 'book-reviews'),
293
+ 'labels' => $labels,
294
+ 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'comments'),
295
+ 'taxonomies' => array('book_genre'),
296
+ 'hierarchical' => false,
297
+ 'public' => true,
298
+ 'show_ui' => true,
299
+ 'show_in_menu' => true,
300
+ 'menu_position' => 5,
301
+ 'menu_icon' => 'dashicons-book',
302
+ 'show_in_admin_bar' => true,
303
+ 'show_in_nav_menus' => true,
304
+ 'can_export' => true,
305
+ 'has_archive' => true,
306
+ 'exclude_from_search' => false,
307
+ 'publicly_queryable' => true,
308
+ 'capability_type' => 'post',
309
+ 'show_in_rest' => true,
310
+ 'rewrite' => array('slug' => 'book-reviews'),
311
+ );
312
+
313
+ register_post_type('book_review', $args);
314
+ }
315
+ }
316
+ ```
317
+
318
+ ### Custom Taxonomy Class
319
+
320
+ **File**: `includes/class-book-genre-taxonomy.php`
321
+
322
+ ```php
323
+ <?php
324
+ /**
325
+ * Register the Book Genre custom taxonomy.
326
+ */
327
+ class Book_Genre_Taxonomy {
328
+
329
+ /**
330
+ * Register the custom taxonomy.
331
+ */
332
+ public function register() {
333
+ $labels = array(
334
+ 'name' => _x('Book Genres', 'Taxonomy General Name', 'book-reviews'),
335
+ 'singular_name' => _x('Book Genre', 'Taxonomy Singular Name', 'book-reviews'),
336
+ 'menu_name' => __('Book Genres', 'book-reviews'),
337
+ 'all_items' => __('All Book Genres', 'book-reviews'),
338
+ 'parent_item' => __('Parent Book Genre', 'book-reviews'),
339
+ 'parent_item_colon' => __('Parent Book Genre:', 'book-reviews'),
340
+ 'new_item_name' => __('New Book Genre Name', 'book-reviews'),
341
+ 'add_new_item' => __('Add New Book Genre', 'book-reviews'),
342
+ 'edit_item' => __('Edit Book Genre', 'book-reviews'),
343
+ 'update_item' => __('Update Book Genre', 'book-reviews'),
344
+ 'view_item' => __('View Book Genre', 'book-reviews'),
345
+ 'separate_items_with_commas' => __('Separate genres with commas', 'book-reviews'),
346
+ 'add_or_remove_items' => __('Add or remove genres', 'book-reviews'),
347
+ 'choose_from_most_used' => __('Choose from the most used', 'book-reviews'),
348
+ 'popular_items' => __('Popular Genres', 'book-reviews'),
349
+ 'search_items' => __('Search Genres', 'book-reviews'),
350
+ 'not_found' => __('Not Found', 'book-reviews'),
351
+ 'no_terms' => __('No genres', 'book-reviews'),
352
+ 'items_list' => __('Genres list', 'book-reviews'),
353
+ 'items_list_navigation' => __('Genres list navigation', 'book-reviews'),
354
+ );
355
+
356
+ $args = array(
357
+ 'labels' => $labels,
358
+ 'hierarchical' => true,
359
+ 'public' => true,
360
+ 'show_ui' => true,
361
+ 'show_admin_column' => true,
362
+ 'show_in_nav_menus' => true,
363
+ 'show_tagcloud' => true,
364
+ 'show_in_rest' => true,
365
+ 'rewrite' => array('slug' => 'book-genre'),
366
+ );
367
+
368
+ register_taxonomy('book_genre', array('book_review'), $args);
369
+ }
370
+ }
371
+ ```
372
+
373
+ ### Admin Class with Meta Boxes
374
+
375
+ **File**: `admin/class-book-reviews-admin.php`
376
+
377
+ ```php
378
+ <?php
379
+ /**
380
+ * The admin-specific functionality of the plugin.
381
+ */
382
+ class Book_Reviews_Admin {
383
+
384
+ /**
385
+ * The ID of this plugin.
386
+ */
387
+ private $plugin_name;
388
+
389
+ /**
390
+ * The version of this plugin.
391
+ */
392
+ private $version;
393
+
394
+ /**
395
+ * Initialize the class and set its properties.
396
+ */
397
+ public function __construct($plugin_name, $version) {
398
+ $this->plugin_name = $plugin_name;
399
+ $this->version = $version;
400
+
401
+ add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
402
+ add_action('save_post_book_review', array($this, 'save_meta_boxes'), 10, 2);
403
+ add_filter('manage_book_review_posts_columns', array($this, 'add_custom_columns'));
404
+ add_action('manage_book_review_posts_custom_column', array($this, 'render_custom_columns'), 10, 2);
405
+ }
406
+
407
+ /**
408
+ * Register the stylesheets for the admin area.
409
+ */
410
+ public function enqueue_styles() {
411
+ wp_enqueue_style(
412
+ $this->plugin_name,
413
+ BOOK_REVIEWS_PLUGIN_URL . 'admin/css/book-reviews-admin.css',
414
+ array(),
415
+ $this->version,
416
+ 'all'
417
+ );
418
+ }
419
+
420
+ /**
421
+ * Register the JavaScript for the admin area.
422
+ */
423
+ public function enqueue_scripts() {
424
+ wp_enqueue_script(
425
+ $this->plugin_name,
426
+ BOOK_REVIEWS_PLUGIN_URL . 'admin/js/book-reviews-admin.js',
427
+ array('jquery'),
428
+ $this->version,
429
+ false
430
+ );
431
+ }
432
+
433
+ /**
434
+ * Add meta boxes for book review details.
435
+ */
436
+ public function add_meta_boxes() {
437
+ add_meta_box(
438
+ 'book_review_details',
439
+ __('Book Details', 'book-reviews'),
440
+ array($this, 'render_book_details_meta_box'),
441
+ 'book_review',
442
+ 'normal',
443
+ 'high'
444
+ );
445
+
446
+ add_meta_box(
447
+ 'book_review_rating',
448
+ __('Book Rating', 'book-reviews'),
449
+ array($this, 'render_book_rating_meta_box'),
450
+ 'book_review',
451
+ 'side',
452
+ 'default'
453
+ );
454
+ }
455
+
456
+ /**
457
+ * Render the book details meta box.
458
+ */
459
+ public function render_book_details_meta_box($post) {
460
+ // Add nonce for security
461
+ wp_nonce_field('book_review_details_nonce', 'book_review_details_nonce_field');
462
+
463
+ // Get current values
464
+ $author = get_post_meta($post->ID, '_book_author', true);
465
+ $isbn = get_post_meta($post->ID, '_book_isbn', true);
466
+ $publisher = get_post_meta($post->ID, '_book_publisher', true);
467
+ $publication_date = get_post_meta($post->ID, '_book_publication_date', true);
468
+
469
+ ?>
470
+ <table class="form-table">
471
+ <tr>
472
+ <th><label for="book_author"><?php _e('Author', 'book-reviews'); ?></label></th>
473
+ <td>
474
+ <input type="text"
475
+ id="book_author"
476
+ name="book_author"
477
+ value="<?php echo esc_attr($author); ?>"
478
+ class="regular-text" />
479
+ </td>
480
+ </tr>
481
+ <tr>
482
+ <th><label for="book_isbn"><?php _e('ISBN', 'book-reviews'); ?></label></th>
483
+ <td>
484
+ <input type="text"
485
+ id="book_isbn"
486
+ name="book_isbn"
487
+ value="<?php echo esc_attr($isbn); ?>"
488
+ class="regular-text" />
489
+ </td>
490
+ </tr>
491
+ <tr>
492
+ <th><label for="book_publisher"><?php _e('Publisher', 'book-reviews'); ?></label></th>
493
+ <td>
494
+ <input type="text"
495
+ id="book_publisher"
496
+ name="book_publisher"
497
+ value="<?php echo esc_attr($publisher); ?>"
498
+ class="regular-text" />
499
+ </td>
500
+ </tr>
501
+ <tr>
502
+ <th><label for="book_publication_date"><?php _e('Publication Date', 'book-reviews'); ?></label></th>
503
+ <td>
504
+ <input type="date"
505
+ id="book_publication_date"
506
+ name="book_publication_date"
507
+ value="<?php echo esc_attr($publication_date); ?>" />
508
+ </td>
509
+ </tr>
510
+ </table>
511
+ <?php
512
+ }
513
+
514
+ /**
515
+ * Render the book rating meta box.
516
+ */
517
+ public function render_book_rating_meta_box($post) {
518
+ // Add nonce for security
519
+ wp_nonce_field('book_review_rating_nonce', 'book_review_rating_nonce_field');
520
+
521
+ // Get current value
522
+ $rating = get_post_meta($post->ID, '_book_rating', true);
523
+
524
+ ?>
525
+ <p>
526
+ <label for="book_rating"><?php _e('Rating (1-5 stars)', 'book-reviews'); ?></label>
527
+ <select id="book_rating" name="book_rating">
528
+ <option value=""><?php _e('Select rating', 'book-reviews'); ?></option>
529
+ <?php for ($i = 1; $i <= 5; $i++) : ?>
530
+ <option value="<?php echo $i; ?>" <?php selected($rating, $i); ?>>
531
+ <?php echo str_repeat('★', $i); ?>
532
+ </option>
533
+ <?php endfor; ?>
534
+ </select>
535
+ </p>
536
+ <?php
537
+ }
538
+
539
+ /**
540
+ * Save meta box data.
541
+ */
542
+ public function save_meta_boxes($post_id, $post) {
543
+ // Check if nonce is set
544
+ if (!isset($_POST['book_review_details_nonce_field']) ||
545
+ !isset($_POST['book_review_rating_nonce_field'])) {
546
+ return;
547
+ }
548
+
549
+ // Verify nonces
550
+ if (!wp_verify_nonce($_POST['book_review_details_nonce_field'], 'book_review_details_nonce') ||
551
+ !wp_verify_nonce($_POST['book_review_rating_nonce_field'], 'book_review_rating_nonce')) {
552
+ return;
553
+ }
554
+
555
+ // Check if this is an autosave
556
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
557
+ return;
558
+ }
559
+
560
+ // Check user permissions
561
+ if (!current_user_can('edit_post', $post_id)) {
562
+ return;
563
+ }
564
+
565
+ // Save book details
566
+ if (isset($_POST['book_author'])) {
567
+ update_post_meta($post_id, '_book_author', sanitize_text_field($_POST['book_author']));
568
+ }
569
+
570
+ if (isset($_POST['book_isbn'])) {
571
+ update_post_meta($post_id, '_book_isbn', sanitize_text_field($_POST['book_isbn']));
572
+ }
573
+
574
+ if (isset($_POST['book_publisher'])) {
575
+ update_post_meta($post_id, '_book_publisher', sanitize_text_field($_POST['book_publisher']));
576
+ }
577
+
578
+ if (isset($_POST['book_publication_date'])) {
579
+ update_post_meta($post_id, '_book_publication_date', sanitize_text_field($_POST['book_publication_date']));
580
+ }
581
+
582
+ // Save rating
583
+ if (isset($_POST['book_rating'])) {
584
+ $rating = intval($_POST['book_rating']);
585
+ if ($rating >= 1 && $rating <= 5) {
586
+ update_post_meta($post_id, '_book_rating', $rating);
587
+ }
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Add custom columns to the book review list.
593
+ */
594
+ public function add_custom_columns($columns) {
595
+ $new_columns = array();
596
+
597
+ foreach ($columns as $key => $value) {
598
+ $new_columns[$key] = $value;
599
+
600
+ // Add custom columns after title
601
+ if ($key === 'title') {
602
+ $new_columns['book_author'] = __('Author', 'book-reviews');
603
+ $new_columns['book_rating'] = __('Rating', 'book-reviews');
604
+ $new_columns['book_genre'] = __('Genre', 'book-reviews');
605
+ }
606
+ }
607
+
608
+ return $new_columns;
609
+ }
610
+
611
+ /**
612
+ * Render custom column content.
613
+ */
614
+ public function render_custom_columns($column, $post_id) {
615
+ switch ($column) {
616
+ case 'book_author':
617
+ $author = get_post_meta($post_id, '_book_author', true);
618
+ echo esc_html($author);
619
+ break;
620
+
621
+ case 'book_rating':
622
+ $rating = get_post_meta($post_id, '_book_rating', true);
623
+ if ($rating) {
624
+ echo str_repeat('★', intval($rating));
625
+ } else {
626
+ echo '—';
627
+ }
628
+ break;
629
+
630
+ case 'book_genre':
631
+ $terms = get_the_terms($post_id, 'book_genre');
632
+ if ($terms && !is_wp_error($terms)) {
633
+ $genre_names = array();
634
+ foreach ($terms as $term) {
635
+ $genre_names[] = esc_html($term->name);
636
+ }
637
+ echo implode(', ', $genre_names);
638
+ } else {
639
+ echo '—';
640
+ }
641
+ break;
642
+ }
643
+ }
644
+ }
645
+ ```
646
+
647
+ ### Public Class with Shortcode
648
+
649
+ **File**: `public/class-book-reviews-public.php`
650
+
651
+ ```php
652
+ <?php
653
+ /**
654
+ * The public-facing functionality of the plugin.
655
+ */
656
+ class Book_Reviews_Public {
657
+
658
+ /**
659
+ * The ID of this plugin.
660
+ */
661
+ private $plugin_name;
662
+
663
+ /**
664
+ * The version of this plugin.
665
+ */
666
+ private $version;
667
+
668
+ /**
669
+ * Initialize the class and set its properties.
670
+ */
671
+ public function __construct($plugin_name, $version) {
672
+ $this->plugin_name = $plugin_name;
673
+ $this->version = $version;
674
+
675
+ add_shortcode('book_reviews', array($this, 'book_reviews_shortcode'));
676
+ add_filter('the_content', array($this, 'add_rating_to_content'));
677
+ }
678
+
679
+ /**
680
+ * Register the stylesheets for the public-facing side of the site.
681
+ */
682
+ public function enqueue_styles() {
683
+ wp_enqueue_style(
684
+ $this->plugin_name,
685
+ BOOK_REVIEWS_PLUGIN_URL . 'public/css/book-reviews-public.css',
686
+ array(),
687
+ $this->version,
688
+ 'all'
689
+ );
690
+ }
691
+
692
+ /**
693
+ * Register the JavaScript for the public-facing side of the site.
694
+ */
695
+ public function enqueue_scripts() {
696
+ wp_enqueue_script(
697
+ $this->plugin_name,
698
+ BOOK_REVIEWS_PLUGIN_URL . 'public/js/book-reviews-public.js',
699
+ array('jquery'),
700
+ $this->version,
701
+ false
702
+ );
703
+ }
704
+
705
+ /**
706
+ * Shortcode to display book reviews.
707
+ *
708
+ * Usage: [book_reviews genre="fiction" limit="5"]
709
+ */
710
+ public function book_reviews_shortcode($atts) {
711
+ $atts = shortcode_atts(array(
712
+ 'genre' => '',
713
+ 'limit' => 10,
714
+ 'orderby' => 'date',
715
+ 'order' => 'DESC',
716
+ ), $atts, 'book_reviews');
717
+
718
+ $args = array(
719
+ 'post_type' => 'book_review',
720
+ 'posts_per_page' => intval($atts['limit']),
721
+ 'orderby' => sanitize_text_field($atts['orderby']),
722
+ 'order' => sanitize_text_field($atts['order']),
723
+ );
724
+
725
+ // Add genre filter if specified
726
+ if (!empty($atts['genre'])) {
727
+ $args['tax_query'] = array(
728
+ array(
729
+ 'taxonomy' => 'book_genre',
730
+ 'field' => 'slug',
731
+ 'terms' => sanitize_text_field($atts['genre']),
732
+ ),
733
+ );
734
+ }
735
+
736
+ $query = new WP_Query($args);
737
+
738
+ ob_start();
739
+
740
+ if ($query->have_posts()) {
741
+ echo '<div class="book-reviews-grid">';
742
+
743
+ while ($query->have_posts()) {
744
+ $query->the_post();
745
+ $this->render_book_review_card(get_the_ID());
746
+ }
747
+
748
+ echo '</div>';
749
+ } else {
750
+ echo '<p>' . esc_html__('No book reviews found.', 'book-reviews') . '</p>';
751
+ }
752
+
753
+ wp_reset_postdata();
754
+
755
+ return ob_get_clean();
756
+ }
757
+
758
+ /**
759
+ * Render a single book review card.
760
+ */
761
+ private function render_book_review_card($post_id) {
762
+ $author = get_post_meta($post_id, '_book_author', true);
763
+ $rating = get_post_meta($post_id, '_book_rating', true);
764
+ $genres = get_the_terms($post_id, 'book_genre');
765
+
766
+ ?>
767
+ <div class="book-review-card">
768
+ <?php if (has_post_thumbnail($post_id)) : ?>
769
+ <div class="book-cover">
770
+ <?php echo get_the_post_thumbnail($post_id, 'medium'); ?>
771
+ </div>
772
+ <?php endif; ?>
773
+
774
+ <div class="book-info">
775
+ <h3 class="book-title">
776
+ <a href="<?php echo esc_url(get_permalink($post_id)); ?>">
777
+ <?php echo esc_html(get_the_title($post_id)); ?>
778
+ </a>
779
+ </h3>
780
+
781
+ <?php if ($author) : ?>
782
+ <p class="book-author">
783
+ <?php _e('by', 'book-reviews'); ?>
784
+ <strong><?php echo esc_html($author); ?></strong>
785
+ </p>
786
+ <?php endif; ?>
787
+
788
+ <?php if ($rating) : ?>
789
+ <div class="book-rating">
790
+ <?php echo str_repeat('★', intval($rating)); ?>
791
+ <?php echo str_repeat('☆', 5 - intval($rating)); ?>
792
+ </div>
793
+ <?php endif; ?>
794
+
795
+ <?php if ($genres && !is_wp_error($genres)) : ?>
796
+ <div class="book-genres">
797
+ <?php foreach ($genres as $genre) : ?>
798
+ <span class="genre-tag"><?php echo esc_html($genre->name); ?></span>
799
+ <?php endforeach; ?>
800
+ </div>
801
+ <?php endif; ?>
802
+
803
+ <div class="book-excerpt">
804
+ <?php echo wp_trim_words(get_the_excerpt($post_id), 20); ?>
805
+ </div>
806
+
807
+ <a href="<?php echo esc_url(get_permalink($post_id)); ?>" class="read-more">
808
+ <?php _e('Read Review', 'book-reviews'); ?>
809
+ </a>
810
+ </div>
811
+ </div>
812
+ <?php
813
+ }
814
+
815
+ /**
816
+ * Add rating to single book review content.
817
+ */
818
+ public function add_rating_to_content($content) {
819
+ if (!is_singular('book_review')) {
820
+ return $content;
821
+ }
822
+
823
+ $post_id = get_the_ID();
824
+ $author = get_post_meta($post_id, '_book_author', true);
825
+ $rating = get_post_meta($post_id, '_book_rating', true);
826
+ $isbn = get_post_meta($post_id, '_book_isbn', true);
827
+ $publisher = get_post_meta($post_id, '_book_publisher', true);
828
+ $publication_date = get_post_meta($post_id, '_book_publication_date', true);
829
+
830
+ ob_start();
831
+ ?>
832
+ <div class="book-review-details">
833
+ <div class="book-meta">
834
+ <?php if ($author) : ?>
835
+ <p><strong><?php _e('Author:', 'book-reviews'); ?></strong> <?php echo esc_html($author); ?></p>
836
+ <?php endif; ?>
837
+
838
+ <?php if ($publisher) : ?>
839
+ <p><strong><?php _e('Publisher:', 'book-reviews'); ?></strong> <?php echo esc_html($publisher); ?></p>
840
+ <?php endif; ?>
841
+
842
+ <?php if ($publication_date) : ?>
843
+ <p><strong><?php _e('Publication Date:', 'book-reviews'); ?></strong> <?php echo esc_html($publication_date); ?></p>
844
+ <?php endif; ?>
845
+
846
+ <?php if ($isbn) : ?>
847
+ <p><strong><?php _e('ISBN:', 'book-reviews'); ?></strong> <?php echo esc_html($isbn); ?></p>
848
+ <?php endif; ?>
849
+
850
+ <?php if ($rating) : ?>
851
+ <div class="book-rating-large">
852
+ <strong><?php _e('Rating:', 'book-reviews'); ?></strong>
853
+ <span class="stars">
854
+ <?php echo str_repeat('★', intval($rating)); ?>
855
+ <?php echo str_repeat('☆', 5 - intval($rating)); ?>
856
+ </span>
857
+ <span class="rating-number"><?php echo esc_html($rating); ?>/5</span>
858
+ </div>
859
+ <?php endif; ?>
860
+ </div>
861
+ </div>
862
+ <?php
863
+ $details = ob_get_clean();
864
+
865
+ return $details . $content;
866
+ }
867
+ }
868
+ ```
869
+
870
+ ### CSS Styling
871
+
872
+ **File**: `public/css/book-reviews-public.css`
873
+
874
+ ```css
875
+ /* Book Reviews Grid */
876
+ .book-reviews-grid {
877
+ display: grid;
878
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
879
+ gap: 2rem;
880
+ margin: 2rem 0;
881
+ }
882
+
883
+ /* Book Review Card */
884
+ .book-review-card {
885
+ border: 1px solid #ddd;
886
+ border-radius: 8px;
887
+ overflow: hidden;
888
+ transition: box-shadow 0.3s ease;
889
+ }
890
+
891
+ .book-review-card:hover {
892
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
893
+ }
894
+
895
+ .book-cover {
896
+ width: 100%;
897
+ height: 400px;
898
+ overflow: hidden;
899
+ background: #f5f5f5;
900
+ }
901
+
902
+ .book-cover img {
903
+ width: 100%;
904
+ height: 100%;
905
+ object-fit: cover;
906
+ }
907
+
908
+ .book-info {
909
+ padding: 1.5rem;
910
+ }
911
+
912
+ .book-title {
913
+ margin: 0 0 0.5rem;
914
+ font-size: 1.25rem;
915
+ }
916
+
917
+ .book-title a {
918
+ color: #333;
919
+ text-decoration: none;
920
+ }
921
+
922
+ .book-title a:hover {
923
+ color: #0073aa;
924
+ }
925
+
926
+ .book-author {
927
+ margin: 0 0 1rem;
928
+ color: #666;
929
+ font-size: 0.95rem;
930
+ }
931
+
932
+ .book-rating {
933
+ margin: 0 0 1rem;
934
+ color: #f39c12;
935
+ font-size: 1.2rem;
936
+ }
937
+
938
+ .book-genres {
939
+ margin: 0 0 1rem;
940
+ }
941
+
942
+ .genre-tag {
943
+ display: inline-block;
944
+ padding: 0.25rem 0.75rem;
945
+ margin: 0 0.5rem 0.5rem 0;
946
+ background: #e8f4f8;
947
+ color: #0073aa;
948
+ border-radius: 4px;
949
+ font-size: 0.85rem;
950
+ }
951
+
952
+ .book-excerpt {
953
+ margin: 0 0 1rem;
954
+ color: #666;
955
+ line-height: 1.6;
956
+ }
957
+
958
+ .read-more {
959
+ display: inline-block;
960
+ padding: 0.5rem 1rem;
961
+ background: #0073aa;
962
+ color: #fff;
963
+ text-decoration: none;
964
+ border-radius: 4px;
965
+ transition: background 0.3s ease;
966
+ }
967
+
968
+ .read-more:hover {
969
+ background: #005a87;
970
+ }
971
+
972
+ /* Single Book Review */
973
+ .book-review-details {
974
+ padding: 1.5rem;
975
+ margin: 0 0 2rem;
976
+ background: #f9f9f9;
977
+ border-left: 4px solid #0073aa;
978
+ }
979
+
980
+ .book-meta p {
981
+ margin: 0.5rem 0;
982
+ }
983
+
984
+ .book-rating-large {
985
+ margin: 1rem 0 0;
986
+ font-size: 1.1rem;
987
+ }
988
+
989
+ .book-rating-large .stars {
990
+ color: #f39c12;
991
+ font-size: 1.5rem;
992
+ margin: 0 0.5rem;
993
+ }
994
+
995
+ .rating-number {
996
+ color: #666;
997
+ font-size: 0.95rem;
998
+ }
999
+ ```
1000
+
1001
+ ## Usage Examples
1002
+
1003
+ ### Display All Book Reviews
1004
+
1005
+ ```
1006
+ [book_reviews]
1007
+ ```
1008
+
1009
+ ### Display Fiction Book Reviews
1010
+
1011
+ ```
1012
+ [book_reviews genre="fiction" limit="5"]
1013
+ ```
1014
+
1015
+ ### Display Latest 3 Reviews
1016
+
1017
+ ```
1018
+ [book_reviews limit="3" orderby="date" order="DESC"]
1019
+ ```
1020
+
1021
+ ## Security Features
1022
+
1023
+ ### 1. Nonce Verification
1024
+
1025
+ All meta box saves verify nonces:
1026
+
1027
+ ```php
1028
+ if (!wp_verify_nonce($_POST['book_review_details_nonce_field'], 'book_review_details_nonce')) {
1029
+ return;
1030
+ }
1031
+ ```
1032
+
1033
+ ### 2. Capability Checks
1034
+
1035
+ Only users with edit permissions can save:
1036
+
1037
+ ```php
1038
+ if (!current_user_can('edit_post', $post_id)) {
1039
+ return;
1040
+ }
1041
+ ```
1042
+
1043
+ ### 3. Input Sanitization
1044
+
1045
+ All inputs are sanitized:
1046
+
1047
+ ```php
1048
+ update_post_meta($post_id, '_book_author', sanitize_text_field($_POST['book_author']));
1049
+ ```
1050
+
1051
+ ### 4. Output Escaping
1052
+
1053
+ All outputs are escaped:
1054
+
1055
+ ```php
1056
+ echo esc_html($author);
1057
+ echo esc_url(get_permalink($post_id));
1058
+ echo esc_attr($isbn);
1059
+ ```
1060
+
1061
+ ### 5. Data Validation
1062
+
1063
+ Rating values are validated:
1064
+
1065
+ ```php
1066
+ $rating = intval($_POST['book_rating']);
1067
+ if ($rating >= 1 && $rating <= 5) {
1068
+ update_post_meta($post_id, '_book_rating', $rating);
1069
+ }
1070
+ ```
1071
+
1072
+ ## Key Takeaways
1073
+
1074
+ - **Custom post types** provide structured content management
1075
+ - **Custom taxonomies** enable categorization and filtering
1076
+ - **Meta boxes** allow additional custom fields
1077
+ - **Custom columns** improve admin list view usability
1078
+ - **Shortcodes** enable flexible frontend display
1079
+ - **Security** is implemented at every level (nonces, capabilities, sanitization, escaping)
1080
+ - **Rewrite rules** must be flushed on activation
1081
+ - **Template hierarchy** can be used for custom templates
1082
+ - **REST API support** enables Gutenberg block editor integration
1083
+