@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.
- package/augment-extensions/domain-rules/wordpress/README.md +163 -0
- package/augment-extensions/domain-rules/wordpress/module.json +32 -0
- package/augment-extensions/domain-rules/wordpress/rules/coding-standards.md +617 -0
- package/augment-extensions/domain-rules/wordpress/rules/directory-structure.md +270 -0
- package/augment-extensions/domain-rules/wordpress/rules/file-patterns.md +423 -0
- package/augment-extensions/domain-rules/wordpress/rules/gutenberg-blocks.md +493 -0
- package/augment-extensions/domain-rules/wordpress/rules/performance.md +568 -0
- package/augment-extensions/domain-rules/wordpress/rules/plugin-development.md +510 -0
- package/augment-extensions/domain-rules/wordpress/rules/project-detection.md +251 -0
- package/augment-extensions/domain-rules/wordpress/rules/rest-api.md +501 -0
- package/augment-extensions/domain-rules/wordpress/rules/security.md +564 -0
- package/augment-extensions/domain-rules/wordpress/rules/theme-development.md +388 -0
- package/augment-extensions/domain-rules/wordpress/rules/woocommerce.md +441 -0
- package/augment-extensions/domain-rules/wordpress-plugin/README.md +139 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/ajax-plugin.md +1599 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/custom-post-type-plugin.md +1727 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block-plugin.md +428 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block.md +422 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/mvc-plugin.md +1623 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/object-oriented-plugin.md +1343 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/rest-endpoint.md +734 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/settings-page-plugin.md +1350 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/simple-procedural-plugin.md +503 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/singleton-plugin.md +971 -0
- package/augment-extensions/domain-rules/wordpress-plugin/module.json +53 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/activation-hooks.md +770 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/admin-interface.md +874 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/ajax-handlers.md +629 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/asset-management.md +559 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/context-providers.md +709 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/cron-jobs.md +736 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/database-management.md +1057 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/documentation-standards.md +463 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/frontend-functionality.md +478 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/gutenberg-blocks.md +818 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/internationalization.md +416 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/migration.md +667 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/performance-optimization.md +878 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-architecture.md +693 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-structure.md +352 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/rest-api.md +818 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/scaffolding-workflow.md +624 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/security-best-practices.md +866 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/testing-patterns.md +1165 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/testing.md +414 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/vscode-integration.md +751 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/woocommerce-integration.md +949 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/wordpress-org-submission.md +458 -0
- package/augment-extensions/examples/gutenberg-block-plugin/README.md +101 -0
- package/augment-extensions/examples/gutenberg-block-plugin/examples/testimonial-block.md +428 -0
- package/augment-extensions/examples/gutenberg-block-plugin/module.json +40 -0
- package/augment-extensions/examples/rest-api-plugin/README.md +98 -0
- package/augment-extensions/examples/rest-api-plugin/examples/task-manager-api.md +1299 -0
- package/augment-extensions/examples/rest-api-plugin/module.json +40 -0
- package/augment-extensions/examples/woocommerce-extension/README.md +98 -0
- package/augment-extensions/examples/woocommerce-extension/examples/product-customizer.md +763 -0
- package/augment-extensions/examples/woocommerce-extension/module.json +40 -0
- package/augment-extensions/workflows/wordpress-plugin/README.md +232 -0
- package/augment-extensions/workflows/wordpress-plugin/ai-prompts.md +839 -0
- package/augment-extensions/workflows/wordpress-plugin/bead-decomposition-patterns.md +854 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/complete-plugin-example.md +540 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/custom-post-type-example.md +1083 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/feature-addition-workflow.md +669 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/plugin-creation-workflow.md +597 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/secure-form-handler-example.md +925 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/security-audit-workflow.md +752 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/wordpress-org-submission-workflow.md +773 -0
- package/augment-extensions/workflows/wordpress-plugin/module.json +49 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/best-practices.md +942 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/development-workflow.md +702 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/submission-workflow.md +728 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/testing-workflow.md +775 -0
- package/cli/dist/cli.js +5 -1
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/show.d.ts.map +1 -1
- package/cli/dist/commands/show.js +41 -0
- package/cli/dist/commands/show.js.map +1 -1
- package/modules.md +52 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1343 @@
|
|
|
1
|
+
# Object-Oriented Plugin Example
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This example demonstrates **Pattern 3: Object-Oriented Plugin** - a maintainable, extensible architecture using classes for complex WordPress plugins.
|
|
6
|
+
|
|
7
|
+
**Complexity**: Medium-High
|
|
8
|
+
**File Count**: 10-30 files
|
|
9
|
+
**Team Size**: 2-5 developers
|
|
10
|
+
**Use Case**: Complex functionality, extensibility, multiple developers, long-term maintenance
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Complete Plugin: "Event Manager Pro"
|
|
15
|
+
|
|
16
|
+
A complete event management plugin demonstrating OOP principles, hook loader pattern, and separation of concerns.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Directory Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
event-manager-pro/
|
|
24
|
+
├── event-manager-pro.php # Main plugin file (bootstrap)
|
|
25
|
+
├── uninstall.php # Uninstall cleanup
|
|
26
|
+
├── readme.txt # WordPress.org readme
|
|
27
|
+
├── includes/
|
|
28
|
+
│ ├── class-event-manager.php # Main plugin class
|
|
29
|
+
│ ├── class-loader.php # Hook loader
|
|
30
|
+
│ ├── class-activator.php # Activation logic
|
|
31
|
+
│ ├── class-deactivator.php # Deactivation logic
|
|
32
|
+
│ ├── class-event.php # Event model
|
|
33
|
+
│ └── class-database.php # Database operations
|
|
34
|
+
├── admin/
|
|
35
|
+
│ ├── class-admin.php # Admin functionality
|
|
36
|
+
│ ├── class-settings.php # Settings page
|
|
37
|
+
│ ├── class-meta-boxes.php # Meta boxes
|
|
38
|
+
│ ├── css/
|
|
39
|
+
│ │ └── admin.css
|
|
40
|
+
│ ├── js/
|
|
41
|
+
│ │ └── admin.js
|
|
42
|
+
│ └── partials/
|
|
43
|
+
│ ├── settings-page.php # Settings view
|
|
44
|
+
│ └── meta-box-event.php # Event meta box view
|
|
45
|
+
├── public/
|
|
46
|
+
│ ├── class-public.php # Public functionality
|
|
47
|
+
│ ├── class-shortcodes.php # Shortcode handlers
|
|
48
|
+
│ ├── class-widgets.php # Widget classes
|
|
49
|
+
│ ├── css/
|
|
50
|
+
│ │ └── public.css
|
|
51
|
+
│ ├── js/
|
|
52
|
+
│ │ └── public.js
|
|
53
|
+
│ └── partials/
|
|
54
|
+
│ ├── event-single.php # Single event view
|
|
55
|
+
│ └── event-list.php # Event list view
|
|
56
|
+
└── languages/
|
|
57
|
+
└── event-manager-pro.pot
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Main Plugin File
|
|
63
|
+
|
|
64
|
+
### File: `event-manager-pro.php`
|
|
65
|
+
|
|
66
|
+
```php
|
|
67
|
+
<?php
|
|
68
|
+
/**
|
|
69
|
+
* Plugin Name: Event Manager Pro
|
|
70
|
+
* Plugin URI: https://example.com/event-manager-pro
|
|
71
|
+
* Description: Professional event management with OOP architecture
|
|
72
|
+
* Version: 1.0.0
|
|
73
|
+
* Author: Your Name
|
|
74
|
+
* Author URI: https://example.com
|
|
75
|
+
* License: GPL-2.0+
|
|
76
|
+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
|
77
|
+
* Text Domain: event-manager-pro
|
|
78
|
+
* Domain Path: /languages
|
|
79
|
+
*
|
|
80
|
+
* @package Event_Manager_Pro
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
// Exit if accessed directly
|
|
84
|
+
if (!defined('ABSPATH')) {
|
|
85
|
+
exit;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Define plugin constants
|
|
89
|
+
define('EMP_VERSION', '1.0.0');
|
|
90
|
+
define('EMP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
|
91
|
+
define('EMP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
|
92
|
+
define('EMP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* PSR-4 Autoloader for plugin classes
|
|
96
|
+
*/
|
|
97
|
+
spl_autoload_register(function ($class) {
|
|
98
|
+
$prefix = 'Event_Manager_Pro_';
|
|
99
|
+
$base_dir = EMP_PLUGIN_DIR . 'includes/';
|
|
100
|
+
|
|
101
|
+
$len = strlen($prefix);
|
|
102
|
+
if (strncmp($prefix, $class, $len) !== 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
$relative_class = substr($class, $len);
|
|
107
|
+
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
|
|
108
|
+
|
|
109
|
+
if (file_exists($file)) {
|
|
110
|
+
require $file;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Load admin classes
|
|
115
|
+
spl_autoload_register(function ($class) {
|
|
116
|
+
if (strpos($class, 'Event_Manager_Pro_Admin') === 0) {
|
|
117
|
+
$file = EMP_PLUGIN_DIR . 'admin/class-' . str_replace('_', '-', strtolower(str_replace('Event_Manager_Pro_Admin_', '', $class))) . '.php';
|
|
118
|
+
if (file_exists($file)) {
|
|
119
|
+
require $file;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Load public classes
|
|
125
|
+
spl_autoload_register(function ($class) {
|
|
126
|
+
if (strpos($class, 'Event_Manager_Pro_Public') === 0) {
|
|
127
|
+
$file = EMP_PLUGIN_DIR . 'public/class-' . str_replace('_', '-', strtolower(str_replace('Event_Manager_Pro_Public_', '', $class))) . '.php';
|
|
128
|
+
if (file_exists($file)) {
|
|
129
|
+
require $file;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Activation hook
|
|
136
|
+
*/
|
|
137
|
+
function activate_event_manager_pro() {
|
|
138
|
+
require_once EMP_PLUGIN_DIR . 'includes/class-activator.php';
|
|
139
|
+
Event_Manager_Pro_Activator::activate();
|
|
140
|
+
}
|
|
141
|
+
register_activation_hook(__FILE__, 'activate_event_manager_pro');
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Deactivation hook
|
|
145
|
+
*/
|
|
146
|
+
function deactivate_event_manager_pro() {
|
|
147
|
+
require_once EMP_PLUGIN_DIR . 'includes/class-deactivator.php';
|
|
148
|
+
Event_Manager_Pro_Deactivator::deactivate();
|
|
149
|
+
}
|
|
150
|
+
register_deactivation_hook(__FILE__, 'deactivate_event_manager_pro');
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Initialize and run the plugin
|
|
154
|
+
*/
|
|
155
|
+
function run_event_manager_pro() {
|
|
156
|
+
$plugin = new Event_Manager_Pro();
|
|
157
|
+
$plugin->run();
|
|
158
|
+
}
|
|
159
|
+
run_event_manager_pro();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Core Classes
|
|
165
|
+
|
|
166
|
+
### File: `includes/class-event-manager.php`
|
|
167
|
+
|
|
168
|
+
```php
|
|
169
|
+
<?php
|
|
170
|
+
/**
|
|
171
|
+
* Main plugin class
|
|
172
|
+
*
|
|
173
|
+
* @package Event_Manager_Pro
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
class Event_Manager_Pro {
|
|
177
|
+
/**
|
|
178
|
+
* The loader that's responsible for maintaining and registering all hooks
|
|
179
|
+
*
|
|
180
|
+
* @var Event_Manager_Pro_Loader
|
|
181
|
+
*/
|
|
182
|
+
protected $loader;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The unique identifier of this plugin
|
|
186
|
+
*
|
|
187
|
+
* @var string
|
|
188
|
+
*/
|
|
189
|
+
protected $plugin_name;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The current version of the plugin
|
|
193
|
+
*
|
|
194
|
+
* @var string
|
|
195
|
+
*/
|
|
196
|
+
protected $version;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Initialize the plugin
|
|
200
|
+
*/
|
|
201
|
+
public function __construct() {
|
|
202
|
+
$this->version = EMP_VERSION;
|
|
203
|
+
$this->plugin_name = 'event-manager-pro';
|
|
204
|
+
|
|
205
|
+
$this->load_dependencies();
|
|
206
|
+
$this->set_locale();
|
|
207
|
+
$this->define_admin_hooks();
|
|
208
|
+
$this->define_public_hooks();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Load required dependencies
|
|
213
|
+
*/
|
|
214
|
+
private function load_dependencies() {
|
|
215
|
+
require_once EMP_PLUGIN_DIR . 'includes/class-loader.php';
|
|
216
|
+
require_once EMP_PLUGIN_DIR . 'includes/class-event.php';
|
|
217
|
+
require_once EMP_PLUGIN_DIR . 'includes/class-database.php';
|
|
218
|
+
require_once EMP_PLUGIN_DIR . 'admin/class-admin.php';
|
|
219
|
+
require_once EMP_PLUGIN_DIR . 'admin/class-settings.php';
|
|
220
|
+
require_once EMP_PLUGIN_DIR . 'admin/class-meta-boxes.php';
|
|
221
|
+
require_once EMP_PLUGIN_DIR . 'public/class-public.php';
|
|
222
|
+
require_once EMP_PLUGIN_DIR . 'public/class-shortcodes.php';
|
|
223
|
+
|
|
224
|
+
$this->loader = new Event_Manager_Pro_Loader();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set the plugin locale for internationalization
|
|
229
|
+
*/
|
|
230
|
+
private function set_locale() {
|
|
231
|
+
$this->loader->add_action('plugins_loaded', $this, 'load_plugin_textdomain');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Load plugin text domain
|
|
236
|
+
*/
|
|
237
|
+
public function load_plugin_textdomain() {
|
|
238
|
+
load_plugin_textdomain(
|
|
239
|
+
'event-manager-pro',
|
|
240
|
+
false,
|
|
241
|
+
dirname(EMP_PLUGIN_BASENAME) . '/languages/'
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Register all admin-related hooks
|
|
247
|
+
*/
|
|
248
|
+
private function define_admin_hooks() {
|
|
249
|
+
$admin = new Event_Manager_Pro_Admin($this->plugin_name, $this->version);
|
|
250
|
+
|
|
251
|
+
// Admin menu and assets
|
|
252
|
+
$this->loader->add_action('admin_menu', $admin, 'add_admin_menu');
|
|
253
|
+
$this->loader->add_action('admin_enqueue_scripts', $admin, 'enqueue_styles');
|
|
254
|
+
$this->loader->add_action('admin_enqueue_scripts', $admin, 'enqueue_scripts');
|
|
255
|
+
|
|
256
|
+
// Settings
|
|
257
|
+
$settings = new Event_Manager_Pro_Admin_Settings($this->plugin_name, $this->version);
|
|
258
|
+
$this->loader->add_action('admin_init', $settings, 'register_settings');
|
|
259
|
+
|
|
260
|
+
// Meta boxes
|
|
261
|
+
$meta_boxes = new Event_Manager_Pro_Admin_Meta_Boxes($this->plugin_name, $this->version);
|
|
262
|
+
$this->loader->add_action('add_meta_boxes', $meta_boxes, 'add_meta_boxes');
|
|
263
|
+
$this->loader->add_action('save_post', $meta_boxes, 'save_meta_boxes');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Register all public-facing hooks
|
|
268
|
+
*/
|
|
269
|
+
private function define_public_hooks() {
|
|
270
|
+
$public = new Event_Manager_Pro_Public($this->plugin_name, $this->version);
|
|
271
|
+
|
|
272
|
+
// Public assets
|
|
273
|
+
$this->loader->add_action('wp_enqueue_scripts', $public, 'enqueue_styles');
|
|
274
|
+
$this->loader->add_action('wp_enqueue_scripts', $public, 'enqueue_scripts');
|
|
275
|
+
|
|
276
|
+
// Custom post type
|
|
277
|
+
$this->loader->add_action('init', $public, 'register_event_post_type');
|
|
278
|
+
|
|
279
|
+
// Shortcodes
|
|
280
|
+
$shortcodes = new Event_Manager_Pro_Public_Shortcodes($this->plugin_name, $this->version);
|
|
281
|
+
$this->loader->add_action('init', $shortcodes, 'register_shortcodes');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Run the loader to execute all hooks
|
|
286
|
+
*/
|
|
287
|
+
public function run() {
|
|
288
|
+
$this->loader->run();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Get the plugin name
|
|
293
|
+
*
|
|
294
|
+
* @return string
|
|
295
|
+
*/
|
|
296
|
+
public function get_plugin_name() {
|
|
297
|
+
return $this->plugin_name;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get the plugin version
|
|
302
|
+
*
|
|
303
|
+
* @return string
|
|
304
|
+
*/
|
|
305
|
+
public function get_version() {
|
|
306
|
+
return $this->version;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Get the loader
|
|
311
|
+
*
|
|
312
|
+
* @return Event_Manager_Pro_Loader
|
|
313
|
+
*/
|
|
314
|
+
public function get_loader() {
|
|
315
|
+
return $this->loader;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### File: `includes/class-loader.php`
|
|
321
|
+
|
|
322
|
+
```php
|
|
323
|
+
<?php
|
|
324
|
+
/**
|
|
325
|
+
* Hook loader class
|
|
326
|
+
*
|
|
327
|
+
* Maintains and registers all hooks for the plugin
|
|
328
|
+
*
|
|
329
|
+
* @package Event_Manager_Pro
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
class Event_Manager_Pro_Loader {
|
|
333
|
+
/**
|
|
334
|
+
* Array of actions registered with WordPress
|
|
335
|
+
*
|
|
336
|
+
* @var array
|
|
337
|
+
*/
|
|
338
|
+
protected $actions;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Array of filters registered with WordPress
|
|
342
|
+
*
|
|
343
|
+
* @var array
|
|
344
|
+
*/
|
|
345
|
+
protected $filters;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Initialize the collections
|
|
349
|
+
*/
|
|
350
|
+
public function __construct() {
|
|
351
|
+
$this->actions = array();
|
|
352
|
+
$this->filters = array();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Add a new action to the collection
|
|
357
|
+
*
|
|
358
|
+
* @param string $hook The name of the WordPress action
|
|
359
|
+
* @param object $component A reference to the instance of the object
|
|
360
|
+
* @param string $callback The name of the function definition on the $component
|
|
361
|
+
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
|
|
362
|
+
* @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
|
|
363
|
+
*/
|
|
364
|
+
public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
|
|
365
|
+
$this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Add a new filter to the collection
|
|
370
|
+
*
|
|
371
|
+
* @param string $hook The name of the WordPress filter
|
|
372
|
+
* @param object $component A reference to the instance of the object
|
|
373
|
+
* @param string $callback The name of the function definition on the $component
|
|
374
|
+
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
|
|
375
|
+
* @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
|
|
376
|
+
*/
|
|
377
|
+
public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
|
|
378
|
+
$this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Utility function to register hooks
|
|
383
|
+
*
|
|
384
|
+
* @param array $hooks The collection of hooks
|
|
385
|
+
* @param string $hook The name of the WordPress filter/action
|
|
386
|
+
* @param object $component A reference to the instance of the object
|
|
387
|
+
* @param string $callback The name of the function definition on the $component
|
|
388
|
+
* @param int $priority The priority at which the function should be fired
|
|
389
|
+
* @param int $accepted_args The number of arguments that should be passed to the $callback
|
|
390
|
+
* @return array
|
|
391
|
+
*/
|
|
392
|
+
private function add($hooks, $hook, $component, $callback, $priority, $accepted_args) {
|
|
393
|
+
$hooks[] = array(
|
|
394
|
+
'hook' => $hook,
|
|
395
|
+
'component' => $component,
|
|
396
|
+
'callback' => $callback,
|
|
397
|
+
'priority' => $priority,
|
|
398
|
+
'accepted_args' => $accepted_args
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
return $hooks;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Register the filters and actions with WordPress
|
|
406
|
+
*/
|
|
407
|
+
public function run() {
|
|
408
|
+
foreach ($this->filters as $hook) {
|
|
409
|
+
add_filter(
|
|
410
|
+
$hook['hook'],
|
|
411
|
+
array($hook['component'], $hook['callback']),
|
|
412
|
+
$hook['priority'],
|
|
413
|
+
$hook['accepted_args']
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
foreach ($this->actions as $hook) {
|
|
418
|
+
add_action(
|
|
419
|
+
$hook['hook'],
|
|
420
|
+
array($hook['component'], $hook['callback']),
|
|
421
|
+
$hook['priority'],
|
|
422
|
+
$hook['accepted_args']
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### File: `includes/class-activator.php`
|
|
430
|
+
|
|
431
|
+
```php
|
|
432
|
+
<?php
|
|
433
|
+
/**
|
|
434
|
+
* Activation handler
|
|
435
|
+
*
|
|
436
|
+
* @package Event_Manager_Pro
|
|
437
|
+
*/
|
|
438
|
+
|
|
439
|
+
class Event_Manager_Pro_Activator {
|
|
440
|
+
/**
|
|
441
|
+
* Activate the plugin
|
|
442
|
+
*/
|
|
443
|
+
public static function activate() {
|
|
444
|
+
// Register custom post type (needed for flush_rewrite_rules)
|
|
445
|
+
self::register_event_post_type();
|
|
446
|
+
|
|
447
|
+
// Flush rewrite rules
|
|
448
|
+
flush_rewrite_rules();
|
|
449
|
+
|
|
450
|
+
// Create custom database tables
|
|
451
|
+
self::create_tables();
|
|
452
|
+
|
|
453
|
+
// Set default options
|
|
454
|
+
self::set_default_options();
|
|
455
|
+
|
|
456
|
+
// Schedule cron events
|
|
457
|
+
if (!wp_next_scheduled('emp_daily_cleanup')) {
|
|
458
|
+
wp_schedule_event(time(), 'daily', 'emp_daily_cleanup');
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Register event post type (temporary for activation)
|
|
464
|
+
*/
|
|
465
|
+
private static function register_event_post_type() {
|
|
466
|
+
register_post_type('emp_event', array(
|
|
467
|
+
'public' => true,
|
|
468
|
+
'has_archive' => true,
|
|
469
|
+
'rewrite' => array('slug' => 'events'),
|
|
470
|
+
));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Create custom database tables
|
|
475
|
+
*/
|
|
476
|
+
private static function create_tables() {
|
|
477
|
+
global $wpdb;
|
|
478
|
+
|
|
479
|
+
$charset_collate = $wpdb->get_charset_collate();
|
|
480
|
+
$table_name = $wpdb->prefix . 'emp_attendees';
|
|
481
|
+
|
|
482
|
+
$sql = "CREATE TABLE $table_name (
|
|
483
|
+
id bigint(20) NOT NULL AUTO_INCREMENT,
|
|
484
|
+
event_id bigint(20) NOT NULL,
|
|
485
|
+
user_id bigint(20) NOT NULL,
|
|
486
|
+
status varchar(20) NOT NULL DEFAULT 'registered',
|
|
487
|
+
registered_at datetime DEFAULT CURRENT_TIMESTAMP,
|
|
488
|
+
PRIMARY KEY (id),
|
|
489
|
+
KEY event_id (event_id),
|
|
490
|
+
KEY user_id (user_id)
|
|
491
|
+
) $charset_collate;";
|
|
492
|
+
|
|
493
|
+
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
|
494
|
+
dbDelta($sql);
|
|
495
|
+
|
|
496
|
+
// Store database version
|
|
497
|
+
add_option('emp_db_version', '1.0.0');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Set default plugin options
|
|
502
|
+
*/
|
|
503
|
+
private static function set_default_options() {
|
|
504
|
+
$defaults = array(
|
|
505
|
+
'events_per_page' => 10,
|
|
506
|
+
'date_format' => 'F j, Y',
|
|
507
|
+
'time_format' => 'g:i a',
|
|
508
|
+
'enable_registration' => true,
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
add_option('emp_settings', $defaults);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### File: `includes/class-deactivator.php`
|
|
517
|
+
|
|
518
|
+
```php
|
|
519
|
+
<?php
|
|
520
|
+
/**
|
|
521
|
+
* Deactivation handler
|
|
522
|
+
*
|
|
523
|
+
* @package Event_Manager_Pro
|
|
524
|
+
*/
|
|
525
|
+
|
|
526
|
+
class Event_Manager_Pro_Deactivator {
|
|
527
|
+
/**
|
|
528
|
+
* Deactivate the plugin
|
|
529
|
+
*/
|
|
530
|
+
public static function deactivate() {
|
|
531
|
+
// Unschedule cron events
|
|
532
|
+
$timestamp = wp_next_scheduled('emp_daily_cleanup');
|
|
533
|
+
if ($timestamp) {
|
|
534
|
+
wp_unschedule_event($timestamp, 'emp_daily_cleanup');
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Flush rewrite rules
|
|
538
|
+
flush_rewrite_rules();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### File: `includes/class-event.php`
|
|
544
|
+
|
|
545
|
+
```php
|
|
546
|
+
<?php
|
|
547
|
+
/**
|
|
548
|
+
* Event model class
|
|
549
|
+
*
|
|
550
|
+
* @package Event_Manager_Pro
|
|
551
|
+
*/
|
|
552
|
+
|
|
553
|
+
class Event_Manager_Pro_Event {
|
|
554
|
+
/**
|
|
555
|
+
* Event ID
|
|
556
|
+
*
|
|
557
|
+
* @var int
|
|
558
|
+
*/
|
|
559
|
+
private $id;
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Event data
|
|
563
|
+
*
|
|
564
|
+
* @var array
|
|
565
|
+
*/
|
|
566
|
+
private $data;
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Constructor
|
|
570
|
+
*
|
|
571
|
+
* @param int $event_id Event post ID
|
|
572
|
+
*/
|
|
573
|
+
public function __construct($event_id = 0) {
|
|
574
|
+
if ($event_id > 0) {
|
|
575
|
+
$this->id = $event_id;
|
|
576
|
+
$this->load();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Load event data
|
|
582
|
+
*/
|
|
583
|
+
private function load() {
|
|
584
|
+
$post = get_post($this->id);
|
|
585
|
+
|
|
586
|
+
if (!$post || $post->post_type !== 'emp_event') {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
$this->data = array(
|
|
591
|
+
'title' => $post->post_title,
|
|
592
|
+
'description' => $post->post_content,
|
|
593
|
+
'start_date' => get_post_meta($this->id, '_emp_start_date', true),
|
|
594
|
+
'end_date' => get_post_meta($this->id, '_emp_end_date', true),
|
|
595
|
+
'location' => get_post_meta($this->id, '_emp_location', true),
|
|
596
|
+
'capacity' => get_post_meta($this->id, '_emp_capacity', true),
|
|
597
|
+
'status' => $post->post_status,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Get event property
|
|
603
|
+
*
|
|
604
|
+
* @param string $key Property key
|
|
605
|
+
* @return mixed
|
|
606
|
+
*/
|
|
607
|
+
public function get($key) {
|
|
608
|
+
return isset($this->data[$key]) ? $this->data[$key] : null;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Set event property
|
|
613
|
+
*
|
|
614
|
+
* @param string $key Property key
|
|
615
|
+
* @param mixed $value Property value
|
|
616
|
+
*/
|
|
617
|
+
public function set($key, $value) {
|
|
618
|
+
$this->data[$key] = $value;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Save event
|
|
623
|
+
*
|
|
624
|
+
* @return int|WP_Error Event ID on success, WP_Error on failure
|
|
625
|
+
*/
|
|
626
|
+
public function save() {
|
|
627
|
+
$post_data = array(
|
|
628
|
+
'post_title' => $this->data['title'],
|
|
629
|
+
'post_content' => $this->data['description'],
|
|
630
|
+
'post_type' => 'emp_event',
|
|
631
|
+
'post_status' => $this->data['status'] ?? 'publish',
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
if ($this->id > 0) {
|
|
635
|
+
$post_data['ID'] = $this->id;
|
|
636
|
+
$result = wp_update_post($post_data, true);
|
|
637
|
+
} else {
|
|
638
|
+
$result = wp_insert_post($post_data, true);
|
|
639
|
+
if (!is_wp_error($result)) {
|
|
640
|
+
$this->id = $result;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (is_wp_error($result)) {
|
|
645
|
+
return $result;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Save meta data
|
|
649
|
+
update_post_meta($this->id, '_emp_start_date', $this->data['start_date']);
|
|
650
|
+
update_post_meta($this->id, '_emp_end_date', $this->data['end_date']);
|
|
651
|
+
update_post_meta($this->id, '_emp_location', $this->data['location']);
|
|
652
|
+
update_post_meta($this->id, '_emp_capacity', $this->data['capacity']);
|
|
653
|
+
|
|
654
|
+
return $this->id;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Delete event
|
|
659
|
+
*
|
|
660
|
+
* @return bool
|
|
661
|
+
*/
|
|
662
|
+
public function delete() {
|
|
663
|
+
if ($this->id > 0) {
|
|
664
|
+
return wp_delete_post($this->id, true) !== false;
|
|
665
|
+
}
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Get attendee count
|
|
671
|
+
*
|
|
672
|
+
* @return int
|
|
673
|
+
*/
|
|
674
|
+
public function get_attendee_count() {
|
|
675
|
+
global $wpdb;
|
|
676
|
+
$table_name = $wpdb->prefix . 'emp_attendees';
|
|
677
|
+
|
|
678
|
+
return (int) $wpdb->get_var($wpdb->prepare(
|
|
679
|
+
"SELECT COUNT(*) FROM $table_name WHERE event_id = %d AND status = 'registered'",
|
|
680
|
+
$this->id
|
|
681
|
+
));
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Check if event is full
|
|
686
|
+
*
|
|
687
|
+
* @return bool
|
|
688
|
+
*/
|
|
689
|
+
public function is_full() {
|
|
690
|
+
$capacity = (int) $this->get('capacity');
|
|
691
|
+
if ($capacity <= 0) {
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return $this->get_attendee_count() >= $capacity;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Get available spots
|
|
700
|
+
*
|
|
701
|
+
* @return int
|
|
702
|
+
*/
|
|
703
|
+
public function get_available_spots() {
|
|
704
|
+
$capacity = (int) $this->get('capacity');
|
|
705
|
+
if ($capacity <= 0) {
|
|
706
|
+
return -1; // Unlimited
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return max(0, $capacity - $this->get_attendee_count());
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## Admin Classes
|
|
717
|
+
|
|
718
|
+
### File: `admin/class-admin.php`
|
|
719
|
+
|
|
720
|
+
```php
|
|
721
|
+
<?php
|
|
722
|
+
/**
|
|
723
|
+
* Admin functionality
|
|
724
|
+
*
|
|
725
|
+
* @package Event_Manager_Pro
|
|
726
|
+
*/
|
|
727
|
+
|
|
728
|
+
class Event_Manager_Pro_Admin {
|
|
729
|
+
private $plugin_name;
|
|
730
|
+
private $version;
|
|
731
|
+
|
|
732
|
+
public function __construct($plugin_name, $version) {
|
|
733
|
+
$this->plugin_name = $plugin_name;
|
|
734
|
+
$this->version = $version;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Add admin menu
|
|
739
|
+
*/
|
|
740
|
+
public function add_admin_menu() {
|
|
741
|
+
add_menu_page(
|
|
742
|
+
__('Event Manager', 'event-manager-pro'),
|
|
743
|
+
__('Events', 'event-manager-pro'),
|
|
744
|
+
'manage_options',
|
|
745
|
+
'event-manager-pro',
|
|
746
|
+
array($this, 'display_admin_page'),
|
|
747
|
+
'dashicons-calendar-alt',
|
|
748
|
+
25
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Display admin page
|
|
754
|
+
*/
|
|
755
|
+
public function display_admin_page() {
|
|
756
|
+
include EMP_PLUGIN_DIR . 'admin/partials/settings-page.php';
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Enqueue admin styles
|
|
761
|
+
*/
|
|
762
|
+
public function enqueue_styles() {
|
|
763
|
+
wp_enqueue_style(
|
|
764
|
+
$this->plugin_name,
|
|
765
|
+
EMP_PLUGIN_URL . 'admin/css/admin.css',
|
|
766
|
+
array(),
|
|
767
|
+
$this->version,
|
|
768
|
+
'all'
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Enqueue admin scripts
|
|
774
|
+
*/
|
|
775
|
+
public function enqueue_scripts() {
|
|
776
|
+
wp_enqueue_script(
|
|
777
|
+
$this->plugin_name,
|
|
778
|
+
EMP_PLUGIN_URL . 'admin/js/admin.js',
|
|
779
|
+
array('jquery', 'jquery-ui-datepicker'),
|
|
780
|
+
$this->version,
|
|
781
|
+
false
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### File: `admin/class-meta-boxes.php`
|
|
788
|
+
|
|
789
|
+
```php
|
|
790
|
+
<?php
|
|
791
|
+
/**
|
|
792
|
+
* Meta boxes for event post type
|
|
793
|
+
*
|
|
794
|
+
* @package Event_Manager_Pro
|
|
795
|
+
*/
|
|
796
|
+
|
|
797
|
+
class Event_Manager_Pro_Admin_Meta_Boxes {
|
|
798
|
+
private $plugin_name;
|
|
799
|
+
private $version;
|
|
800
|
+
|
|
801
|
+
public function __construct($plugin_name, $version) {
|
|
802
|
+
$this->plugin_name = $plugin_name;
|
|
803
|
+
$this->version = $version;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Add meta boxes
|
|
808
|
+
*/
|
|
809
|
+
public function add_meta_boxes() {
|
|
810
|
+
add_meta_box(
|
|
811
|
+
'emp_event_details',
|
|
812
|
+
__('Event Details', 'event-manager-pro'),
|
|
813
|
+
array($this, 'render_event_details_meta_box'),
|
|
814
|
+
'emp_event',
|
|
815
|
+
'normal',
|
|
816
|
+
'high'
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Render event details meta box
|
|
822
|
+
*/
|
|
823
|
+
public function render_event_details_meta_box($post) {
|
|
824
|
+
wp_nonce_field('emp_save_event_details', 'emp_event_details_nonce');
|
|
825
|
+
|
|
826
|
+
$start_date = get_post_meta($post->ID, '_emp_start_date', true);
|
|
827
|
+
$end_date = get_post_meta($post->ID, '_emp_end_date', true);
|
|
828
|
+
$location = get_post_meta($post->ID, '_emp_location', true);
|
|
829
|
+
$capacity = get_post_meta($post->ID, '_emp_capacity', true);
|
|
830
|
+
|
|
831
|
+
include EMP_PLUGIN_DIR . 'admin/partials/meta-box-event.php';
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Save meta box data
|
|
836
|
+
*/
|
|
837
|
+
public function save_meta_boxes($post_id) {
|
|
838
|
+
// Security checks
|
|
839
|
+
if (!isset($_POST['emp_event_details_nonce'])) {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (!wp_verify_nonce($_POST['emp_event_details_nonce'], 'emp_save_event_details')) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (!current_user_can('edit_post', $post_id)) {
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Save meta data
|
|
856
|
+
if (isset($_POST['emp_start_date'])) {
|
|
857
|
+
update_post_meta($post_id, '_emp_start_date', sanitize_text_field($_POST['emp_start_date']));
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (isset($_POST['emp_end_date'])) {
|
|
861
|
+
update_post_meta($post_id, '_emp_end_date', sanitize_text_field($_POST['emp_end_date']));
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (isset($_POST['emp_location'])) {
|
|
865
|
+
update_post_meta($post_id, '_emp_location', sanitize_text_field($_POST['emp_location']));
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (isset($_POST['emp_capacity'])) {
|
|
869
|
+
update_post_meta($post_id, '_emp_capacity', absint($_POST['emp_capacity']));
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## Public Classes
|
|
878
|
+
|
|
879
|
+
### File: `public/class-public.php`
|
|
880
|
+
|
|
881
|
+
```php
|
|
882
|
+
<?php
|
|
883
|
+
/**
|
|
884
|
+
* Public-facing functionality
|
|
885
|
+
*
|
|
886
|
+
* @package Event_Manager_Pro
|
|
887
|
+
*/
|
|
888
|
+
|
|
889
|
+
class Event_Manager_Pro_Public {
|
|
890
|
+
private $plugin_name;
|
|
891
|
+
private $version;
|
|
892
|
+
|
|
893
|
+
public function __construct($plugin_name, $version) {
|
|
894
|
+
$this->plugin_name = $plugin_name;
|
|
895
|
+
$this->version = $version;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Register event custom post type
|
|
900
|
+
*/
|
|
901
|
+
public function register_event_post_type() {
|
|
902
|
+
$labels = array(
|
|
903
|
+
'name' => __('Events', 'event-manager-pro'),
|
|
904
|
+
'singular_name' => __('Event', 'event-manager-pro'),
|
|
905
|
+
'add_new' => __('Add New Event', 'event-manager-pro'),
|
|
906
|
+
'add_new_item' => __('Add New Event', 'event-manager-pro'),
|
|
907
|
+
'edit_item' => __('Edit Event', 'event-manager-pro'),
|
|
908
|
+
'view_item' => __('View Event', 'event-manager-pro'),
|
|
909
|
+
'search_items' => __('Search Events', 'event-manager-pro'),
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
$args = array(
|
|
913
|
+
'labels' => $labels,
|
|
914
|
+
'public' => true,
|
|
915
|
+
'has_archive' => true,
|
|
916
|
+
'menu_icon' => 'dashicons-calendar-alt',
|
|
917
|
+
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
|
|
918
|
+
'rewrite' => array('slug' => 'events'),
|
|
919
|
+
'show_in_rest' => true,
|
|
920
|
+
);
|
|
921
|
+
|
|
922
|
+
register_post_type('emp_event', $args);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Enqueue public styles
|
|
927
|
+
*/
|
|
928
|
+
public function enqueue_styles() {
|
|
929
|
+
wp_enqueue_style(
|
|
930
|
+
$this->plugin_name,
|
|
931
|
+
EMP_PLUGIN_URL . 'public/css/public.css',
|
|
932
|
+
array(),
|
|
933
|
+
$this->version,
|
|
934
|
+
'all'
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Enqueue public scripts
|
|
940
|
+
*/
|
|
941
|
+
public function enqueue_scripts() {
|
|
942
|
+
wp_enqueue_script(
|
|
943
|
+
$this->plugin_name,
|
|
944
|
+
EMP_PLUGIN_URL . 'public/js/public.js',
|
|
945
|
+
array('jquery'),
|
|
946
|
+
$this->version,
|
|
947
|
+
false
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
### File: `public/class-shortcodes.php`
|
|
954
|
+
|
|
955
|
+
```php
|
|
956
|
+
<?php
|
|
957
|
+
/**
|
|
958
|
+
* Shortcode handlers
|
|
959
|
+
*
|
|
960
|
+
* @package Event_Manager_Pro
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
class Event_Manager_Pro_Public_Shortcodes {
|
|
964
|
+
private $plugin_name;
|
|
965
|
+
private $version;
|
|
966
|
+
|
|
967
|
+
public function __construct($plugin_name, $version) {
|
|
968
|
+
$this->plugin_name = $plugin_name;
|
|
969
|
+
$this->version = $version;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Register shortcodes
|
|
974
|
+
*/
|
|
975
|
+
public function register_shortcodes() {
|
|
976
|
+
add_shortcode('event_list', array($this, 'event_list_shortcode'));
|
|
977
|
+
add_shortcode('event_single', array($this, 'event_single_shortcode'));
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Event list shortcode
|
|
982
|
+
*/
|
|
983
|
+
public function event_list_shortcode($atts) {
|
|
984
|
+
$atts = shortcode_atts(array(
|
|
985
|
+
'limit' => 10,
|
|
986
|
+
'order' => 'ASC',
|
|
987
|
+
), $atts);
|
|
988
|
+
|
|
989
|
+
$args = array(
|
|
990
|
+
'post_type' => 'emp_event',
|
|
991
|
+
'posts_per_page' => intval($atts['limit']),
|
|
992
|
+
'order' => $atts['order'],
|
|
993
|
+
'meta_key' => '_emp_start_date',
|
|
994
|
+
'orderby' => 'meta_value',
|
|
995
|
+
);
|
|
996
|
+
|
|
997
|
+
$query = new WP_Query($args);
|
|
998
|
+
|
|
999
|
+
ob_start();
|
|
1000
|
+
if ($query->have_posts()) {
|
|
1001
|
+
include EMP_PLUGIN_DIR . 'public/partials/event-list.php';
|
|
1002
|
+
}
|
|
1003
|
+
wp_reset_postdata();
|
|
1004
|
+
|
|
1005
|
+
return ob_get_clean();
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Single event shortcode
|
|
1010
|
+
*/
|
|
1011
|
+
public function event_single_shortcode($atts) {
|
|
1012
|
+
$atts = shortcode_atts(array(
|
|
1013
|
+
'id' => 0,
|
|
1014
|
+
), $atts);
|
|
1015
|
+
|
|
1016
|
+
$event = new Event_Manager_Pro_Event(intval($atts['id']));
|
|
1017
|
+
|
|
1018
|
+
ob_start();
|
|
1019
|
+
include EMP_PLUGIN_DIR . 'public/partials/event-single.php';
|
|
1020
|
+
return ob_get_clean();
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
## Key OOP Principles Demonstrated
|
|
1028
|
+
|
|
1029
|
+
### 1. **Separation of Concerns**
|
|
1030
|
+
|
|
1031
|
+
✅ **Admin logic** separated from **public logic**
|
|
1032
|
+
✅ **Model** (Event) separated from **controllers** (Admin, Public)
|
|
1033
|
+
✅ **Views** in partials directory
|
|
1034
|
+
|
|
1035
|
+
### 2. **Single Responsibility Principle**
|
|
1036
|
+
|
|
1037
|
+
✅ Each class has one clear purpose:
|
|
1038
|
+
- `Event_Manager_Pro` - Main orchestrator
|
|
1039
|
+
- `Event_Manager_Pro_Loader` - Hook management
|
|
1040
|
+
- `Event_Manager_Pro_Event` - Event data model
|
|
1041
|
+
- `Event_Manager_Pro_Admin` - Admin functionality
|
|
1042
|
+
- `Event_Manager_Pro_Public` - Public functionality
|
|
1043
|
+
|
|
1044
|
+
### 3. **Dependency Injection**
|
|
1045
|
+
|
|
1046
|
+
✅ Plugin name and version injected into classes:
|
|
1047
|
+
```php
|
|
1048
|
+
$admin = new Event_Manager_Pro_Admin($this->plugin_name, $this->version);
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
### 4. **Encapsulation**
|
|
1052
|
+
|
|
1053
|
+
✅ Private/protected properties and methods
|
|
1054
|
+
✅ Public getters/setters for controlled access
|
|
1055
|
+
✅ Data validation in model methods
|
|
1056
|
+
|
|
1057
|
+
### 5. **Hook Loader Pattern**
|
|
1058
|
+
|
|
1059
|
+
✅ Centralized hook management
|
|
1060
|
+
✅ Easy to track all hooks
|
|
1061
|
+
✅ Testable hook registration
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## Advantages of OOP Pattern
|
|
1066
|
+
|
|
1067
|
+
### ✅ Maintainability
|
|
1068
|
+
|
|
1069
|
+
- **Clear structure**: Easy to find and modify code
|
|
1070
|
+
- **Separation of concerns**: Changes isolated to specific classes
|
|
1071
|
+
- **Consistent patterns**: Predictable code organization
|
|
1072
|
+
|
|
1073
|
+
### ✅ Extensibility
|
|
1074
|
+
|
|
1075
|
+
- **Easy to extend**: Add new classes without modifying existing ones
|
|
1076
|
+
- **Inheritance**: Can extend base classes for variations
|
|
1077
|
+
- **Interfaces**: Can define contracts for implementations
|
|
1078
|
+
|
|
1079
|
+
### ✅ Testability
|
|
1080
|
+
|
|
1081
|
+
- **Unit testing**: Each class can be tested independently
|
|
1082
|
+
- **Mocking**: Dependencies can be mocked for testing
|
|
1083
|
+
- **Dependency injection**: Easy to swap implementations
|
|
1084
|
+
|
|
1085
|
+
### ✅ Collaboration
|
|
1086
|
+
|
|
1087
|
+
- **Multiple developers**: Can work on different classes simultaneously
|
|
1088
|
+
- **Code review**: Smaller, focused classes easier to review
|
|
1089
|
+
- **Documentation**: PHPDoc on classes and methods
|
|
1090
|
+
|
|
1091
|
+
### ✅ Reusability
|
|
1092
|
+
|
|
1093
|
+
- **Model classes**: Can be reused across admin and public
|
|
1094
|
+
- **Utility classes**: Shared functionality in dedicated classes
|
|
1095
|
+
- **Composition**: Combine classes for complex functionality
|
|
1096
|
+
|
|
1097
|
+
---
|
|
1098
|
+
|
|
1099
|
+
## When to Use OOP Pattern
|
|
1100
|
+
|
|
1101
|
+
### ✅ Good Use Cases
|
|
1102
|
+
|
|
1103
|
+
- **Complex plugins**: Multiple features and functionality
|
|
1104
|
+
- **Team development**: 2-5 developers working together
|
|
1105
|
+
- **Long-term maintenance**: Plugin will be maintained for years
|
|
1106
|
+
- **Extensibility needed**: Other developers will extend the plugin
|
|
1107
|
+
- **Professional plugins**: Commercial or enterprise plugins
|
|
1108
|
+
- **Testing required**: Unit and integration testing needed
|
|
1109
|
+
|
|
1110
|
+
### ❌ Not Suitable For
|
|
1111
|
+
|
|
1112
|
+
- **Simple plugins**: Single feature, < 200 lines (use Pattern 1)
|
|
1113
|
+
- **Quick prototypes**: Temporary or experimental code
|
|
1114
|
+
- **Solo learning**: Beginners learning WordPress (start with Pattern 1)
|
|
1115
|
+
- **Micro-plugins**: Very specific, focused functionality
|
|
1116
|
+
|
|
1117
|
+
---
|
|
1118
|
+
|
|
1119
|
+
## Best Practices
|
|
1120
|
+
|
|
1121
|
+
### 1. **Class Naming**
|
|
1122
|
+
|
|
1123
|
+
```php
|
|
1124
|
+
// Good
|
|
1125
|
+
class Event_Manager_Pro_Admin { }
|
|
1126
|
+
class Event_Manager_Pro_Public_Shortcodes { }
|
|
1127
|
+
|
|
1128
|
+
// Bad
|
|
1129
|
+
class Admin { } // Too generic
|
|
1130
|
+
class EMP_A { } // Not descriptive
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
### 2. **File Naming**
|
|
1134
|
+
|
|
1135
|
+
```php
|
|
1136
|
+
// Good
|
|
1137
|
+
class-event-manager.php
|
|
1138
|
+
class-admin.php
|
|
1139
|
+
class-shortcodes.php
|
|
1140
|
+
|
|
1141
|
+
// Bad
|
|
1142
|
+
EventManager.php // Wrong case
|
|
1143
|
+
admin.php // Missing prefix
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
### 3. **Autoloading**
|
|
1147
|
+
|
|
1148
|
+
```php
|
|
1149
|
+
// Use PSR-4 style autoloader
|
|
1150
|
+
spl_autoload_register(function ($class) {
|
|
1151
|
+
$prefix = 'Event_Manager_Pro_';
|
|
1152
|
+
$base_dir = EMP_PLUGIN_DIR . 'includes/';
|
|
1153
|
+
|
|
1154
|
+
// Convert class name to file path
|
|
1155
|
+
$relative_class = substr($class, strlen($prefix));
|
|
1156
|
+
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
|
|
1157
|
+
|
|
1158
|
+
if (file_exists($file)) {
|
|
1159
|
+
require $file;
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
### 4. **Dependency Injection**
|
|
1165
|
+
|
|
1166
|
+
```php
|
|
1167
|
+
// Good - Dependencies injected
|
|
1168
|
+
public function __construct($plugin_name, $version, $database) {
|
|
1169
|
+
$this->plugin_name = $plugin_name;
|
|
1170
|
+
$this->version = $version;
|
|
1171
|
+
$this->database = $database;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Bad - Hard-coded dependencies
|
|
1175
|
+
public function __construct() {
|
|
1176
|
+
$this->database = new Database(); // Hard to test
|
|
1177
|
+
}
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
### 5. **Hook Loader**
|
|
1181
|
+
|
|
1182
|
+
```php
|
|
1183
|
+
// Good - Centralized hook management
|
|
1184
|
+
$this->loader->add_action('init', $public, 'register_post_type');
|
|
1185
|
+
$this->loader->add_filter('the_content', $public, 'filter_content');
|
|
1186
|
+
|
|
1187
|
+
// Bad - Direct hook registration in multiple places
|
|
1188
|
+
add_action('init', array($this, 'register_post_type'));
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
### 6. **Model Classes**
|
|
1192
|
+
|
|
1193
|
+
```php
|
|
1194
|
+
// Good - Model with methods
|
|
1195
|
+
$event = new Event_Manager_Pro_Event($event_id);
|
|
1196
|
+
$event->set('title', 'New Event');
|
|
1197
|
+
$event->save();
|
|
1198
|
+
|
|
1199
|
+
// Bad - Direct post meta manipulation
|
|
1200
|
+
update_post_meta($event_id, '_emp_title', 'New Event');
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
### 7. **Security**
|
|
1204
|
+
|
|
1205
|
+
```php
|
|
1206
|
+
// Always sanitize and validate
|
|
1207
|
+
public function save_meta_boxes($post_id) {
|
|
1208
|
+
// Nonce verification
|
|
1209
|
+
if (!wp_verify_nonce($_POST['nonce'], 'save_event')) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// Capability check
|
|
1214
|
+
if (!current_user_can('edit_post', $post_id)) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// Sanitize input
|
|
1219
|
+
$value = sanitize_text_field($_POST['value']);
|
|
1220
|
+
}
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
---
|
|
1224
|
+
|
|
1225
|
+
## Testing Example
|
|
1226
|
+
|
|
1227
|
+
### Unit Test for Event Model
|
|
1228
|
+
|
|
1229
|
+
```php
|
|
1230
|
+
<?php
|
|
1231
|
+
class Event_Test extends WP_UnitTestCase {
|
|
1232
|
+
public function test_event_creation() {
|
|
1233
|
+
$event = new Event_Manager_Pro_Event();
|
|
1234
|
+
$event->set('title', 'Test Event');
|
|
1235
|
+
$event->set('start_date', '2024-01-01');
|
|
1236
|
+
|
|
1237
|
+
$event_id = $event->save();
|
|
1238
|
+
|
|
1239
|
+
$this->assertGreaterThan(0, $event_id);
|
|
1240
|
+
$this->assertEquals('Test Event', get_the_title($event_id));
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
public function test_event_capacity() {
|
|
1244
|
+
$event = new Event_Manager_Pro_Event();
|
|
1245
|
+
$event->set('capacity', 10);
|
|
1246
|
+
$event->save();
|
|
1247
|
+
|
|
1248
|
+
$this->assertEquals(10, $event->get_available_spots());
|
|
1249
|
+
$this->assertFalse($event->is_full());
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
---
|
|
1255
|
+
|
|
1256
|
+
## Comparison with Other Patterns
|
|
1257
|
+
|
|
1258
|
+
| Feature | Simple Procedural | OOP | WPPB |
|
|
1259
|
+
|---------|------------------|-----|------|
|
|
1260
|
+
| **Complexity** | Low | Medium-High | High |
|
|
1261
|
+
| **File Count** | 1-3 | 10-30 | 20-100 |
|
|
1262
|
+
| **Learning Curve** | Easy | Moderate | Steep |
|
|
1263
|
+
| **Maintainability** | Low | High | Very High |
|
|
1264
|
+
| **Testability** | Low | High | Very High |
|
|
1265
|
+
| **Team Size** | 1 | 2-5 | 3-10 |
|
|
1266
|
+
| **Best For** | Simple plugins | Complex plugins | Professional plugins |
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
## Migration Path
|
|
1271
|
+
|
|
1272
|
+
### From Simple Procedural to OOP
|
|
1273
|
+
|
|
1274
|
+
1. **Create main plugin class**
|
|
1275
|
+
2. **Move functions to methods**
|
|
1276
|
+
3. **Create loader class**
|
|
1277
|
+
4. **Separate admin and public**
|
|
1278
|
+
5. **Create model classes**
|
|
1279
|
+
6. **Add autoloader**
|
|
1280
|
+
|
|
1281
|
+
### Example Migration
|
|
1282
|
+
|
|
1283
|
+
**Before (Procedural):**
|
|
1284
|
+
```php
|
|
1285
|
+
function emp_register_post_type() {
|
|
1286
|
+
register_post_type('emp_event', array(...));
|
|
1287
|
+
}
|
|
1288
|
+
add_action('init', 'emp_register_post_type');
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
**After (OOP):**
|
|
1292
|
+
```php
|
|
1293
|
+
class Event_Manager_Pro_Public {
|
|
1294
|
+
public function register_event_post_type() {
|
|
1295
|
+
register_post_type('emp_event', array(...));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
$public = new Event_Manager_Pro_Public($plugin_name, $version);
|
|
1300
|
+
$loader->add_action('init', $public, 'register_event_post_type');
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
---
|
|
1304
|
+
|
|
1305
|
+
## Related Patterns
|
|
1306
|
+
|
|
1307
|
+
- **Pattern 1**: [Simple Procedural Plugin](simple-procedural-plugin.md) - For simple plugins
|
|
1308
|
+
- **Pattern 2**: [Organized Procedural Plugin](organized-procedural-plugin.md) - Medium complexity
|
|
1309
|
+
- **Pattern 4**: [WPPB Plugin](wppb-plugin.md) - Professional standard
|
|
1310
|
+
- **Pattern 5**: [Namespace-Based Plugin](namespace-based-plugin.md) - Modern PHP
|
|
1311
|
+
|
|
1312
|
+
---
|
|
1313
|
+
|
|
1314
|
+
## Additional Resources
|
|
1315
|
+
|
|
1316
|
+
- [WordPress Plugin Handbook - OOP](https://developer.wordpress.org/plugins/plugin-basics/best-practices/#object-oriented-programming-method)
|
|
1317
|
+
- [SOLID Principles in WordPress](https://carlalexander.ca/designing-class-wordpress-hooks/)
|
|
1318
|
+
- [WordPress Plugin Boilerplate](https://wppb.me/)
|
|
1319
|
+
- [PHPUnit for WordPress](https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/)
|
|
1320
|
+
|
|
1321
|
+
---
|
|
1322
|
+
|
|
1323
|
+
## Summary
|
|
1324
|
+
|
|
1325
|
+
This OOP plugin example demonstrates:
|
|
1326
|
+
|
|
1327
|
+
✅ **Complete working plugin** with event management functionality
|
|
1328
|
+
✅ **Proper OOP architecture** with separation of concerns
|
|
1329
|
+
✅ **Hook loader pattern** for centralized hook management
|
|
1330
|
+
✅ **Model class** for data encapsulation
|
|
1331
|
+
✅ **Admin and public separation** for clear organization
|
|
1332
|
+
✅ **Activation/deactivation** handlers
|
|
1333
|
+
✅ **Custom database tables** with proper creation
|
|
1334
|
+
✅ **Meta boxes** with security (nonces, capability checks)
|
|
1335
|
+
✅ **Shortcodes** with proper output buffering
|
|
1336
|
+
✅ **Autoloading** for automatic class loading
|
|
1337
|
+
✅ **Security best practices** throughout
|
|
1338
|
+
✅ **Testable code** structure
|
|
1339
|
+
|
|
1340
|
+
**Perfect for**: Complex plugins, team development, long-term maintenance, professional/commercial plugins.
|
|
1341
|
+
|
|
1342
|
+
**Next steps**: For even more structure, consider Pattern 4 (WPPB) or Pattern 5 (Namespace-Based) for modern PHP with Composer.
|
|
1343
|
+
|