@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,763 @@
|
|
|
1
|
+
# WooCommerce Product Customizer Example
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This example demonstrates a complete **WooCommerce Product Extension** with custom product fields, meta data storage, frontend display, cart integration, order item meta, and admin interfaces.
|
|
6
|
+
|
|
7
|
+
**Complexity**: Medium
|
|
8
|
+
**File Count**: 5-8 files
|
|
9
|
+
**Team Size**: 1-2 developers
|
|
10
|
+
**Use Case**: Product customization, custom fields, personalization, gift messages, engraving
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Complete Plugin: "Product Customizer"
|
|
15
|
+
|
|
16
|
+
A comprehensive WooCommerce extension demonstrating custom product fields, cart item data, order meta, and admin product editing with HPOS compatibility.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Directory Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
product-customizer/
|
|
24
|
+
├── product-customizer.php # Main plugin file
|
|
25
|
+
├── includes/
|
|
26
|
+
│ ├── class-product-fields.php # Product field management
|
|
27
|
+
│ ├── class-cart-handler.php # Cart integration
|
|
28
|
+
│ └── class-order-handler.php # Order meta handling
|
|
29
|
+
├── templates/
|
|
30
|
+
│ └── product-fields.php # Frontend template
|
|
31
|
+
└── readme.txt # WordPress.org readme
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Main Plugin File
|
|
37
|
+
|
|
38
|
+
### File: `product-customizer.php`
|
|
39
|
+
|
|
40
|
+
```php
|
|
41
|
+
<?php
|
|
42
|
+
/**
|
|
43
|
+
* Plugin Name: Product Customizer
|
|
44
|
+
* Plugin URI: https://example.com/product-customizer
|
|
45
|
+
* Description: Add custom fields to WooCommerce products for personalization
|
|
46
|
+
* Version: 1.0.0
|
|
47
|
+
* Requires at least: 5.8
|
|
48
|
+
* Requires PHP: 7.4
|
|
49
|
+
* WC requires at least: 6.0
|
|
50
|
+
* WC tested up to: 8.5
|
|
51
|
+
* Author: Your Name
|
|
52
|
+
* Author URI: https://example.com
|
|
53
|
+
* License: GPL-2.0+
|
|
54
|
+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
|
55
|
+
* Text Domain: product-customizer
|
|
56
|
+
*
|
|
57
|
+
* @package Product_Customizer
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
// Exit if accessed directly
|
|
61
|
+
if (!defined('ABSPATH')) {
|
|
62
|
+
exit;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Define plugin constants
|
|
66
|
+
define('PC_VERSION', '1.0.0');
|
|
67
|
+
define('PC_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
|
68
|
+
define('PC_PLUGIN_URL', plugin_dir_url(__FILE__));
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if WooCommerce is active
|
|
72
|
+
*/
|
|
73
|
+
function pc_check_woocommerce() {
|
|
74
|
+
if (!class_exists('WooCommerce')) {
|
|
75
|
+
add_action('admin_notices', function() {
|
|
76
|
+
?>
|
|
77
|
+
<div class="notice notice-error">
|
|
78
|
+
<p><?php _e('Product Customizer requires WooCommerce to be installed and active.', 'product-customizer'); ?></p>
|
|
79
|
+
</div>
|
|
80
|
+
<?php
|
|
81
|
+
});
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Declare HPOS compatibility
|
|
89
|
+
*/
|
|
90
|
+
add_action('before_woocommerce_init', function() {
|
|
91
|
+
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
|
|
92
|
+
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
|
|
93
|
+
'custom_order_tables',
|
|
94
|
+
__FILE__,
|
|
95
|
+
true
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Autoloader for plugin classes
|
|
102
|
+
*/
|
|
103
|
+
spl_autoload_register(function ($class) {
|
|
104
|
+
$prefix = 'PC_';
|
|
105
|
+
$base_dir = PC_PLUGIN_DIR . 'includes/';
|
|
106
|
+
|
|
107
|
+
$len = strlen($prefix);
|
|
108
|
+
if (strncmp($prefix, $class, $len) !== 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
$relative_class = substr($class, $len);
|
|
113
|
+
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
|
|
114
|
+
|
|
115
|
+
if (file_exists($file)) {
|
|
116
|
+
require $file;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initialize plugin
|
|
122
|
+
*/
|
|
123
|
+
function pc_init() {
|
|
124
|
+
if (!pc_check_woocommerce()) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Initialize classes
|
|
129
|
+
new PC_Product_Fields();
|
|
130
|
+
new PC_Cart_Handler();
|
|
131
|
+
new PC_Order_Handler();
|
|
132
|
+
}
|
|
133
|
+
add_action('plugins_loaded', 'pc_init');
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Load plugin text domain
|
|
137
|
+
*/
|
|
138
|
+
function pc_load_textdomain() {
|
|
139
|
+
load_plugin_textdomain(
|
|
140
|
+
'product-customizer',
|
|
141
|
+
false,
|
|
142
|
+
dirname(plugin_basename(__FILE__)) . '/languages'
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
add_action('init', 'pc_load_textdomain');
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Activation hook
|
|
149
|
+
*/
|
|
150
|
+
register_activation_hook(__FILE__, function() {
|
|
151
|
+
if (!class_exists('WooCommerce')) {
|
|
152
|
+
deactivate_plugins(plugin_basename(__FILE__));
|
|
153
|
+
wp_die(__('Product Customizer requires WooCommerce to be installed and active.', 'product-customizer'));
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Product Fields Class
|
|
161
|
+
|
|
162
|
+
### File: `includes/class-product-fields.php`
|
|
163
|
+
|
|
164
|
+
```php
|
|
165
|
+
<?php
|
|
166
|
+
/**
|
|
167
|
+
* Product Fields
|
|
168
|
+
*
|
|
169
|
+
* @package Product_Customizer
|
|
170
|
+
*/
|
|
171
|
+
|
|
172
|
+
class PC_Product_Fields {
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Constructor
|
|
176
|
+
*/
|
|
177
|
+
public function __construct() {
|
|
178
|
+
// Admin: Add product fields
|
|
179
|
+
add_action('woocommerce_product_options_general_product_data', array($this, 'add_product_fields'));
|
|
180
|
+
add_action('woocommerce_process_product_meta', array($this, 'save_product_fields'));
|
|
181
|
+
|
|
182
|
+
// Frontend: Display custom fields
|
|
183
|
+
add_action('woocommerce_before_add_to_cart_button', array($this, 'display_custom_fields'));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Add custom fields to product admin
|
|
188
|
+
*/
|
|
189
|
+
public function add_product_fields() {
|
|
190
|
+
global $post;
|
|
191
|
+
|
|
192
|
+
echo '<div class="options_group">';
|
|
193
|
+
|
|
194
|
+
// Enable customization checkbox
|
|
195
|
+
woocommerce_wp_checkbox(array(
|
|
196
|
+
'id' => '_enable_customization',
|
|
197
|
+
'label' => __('Enable Customization', 'product-customizer'),
|
|
198
|
+
'description' => __('Allow customers to add custom text to this product.', 'product-customizer'),
|
|
199
|
+
));
|
|
200
|
+
|
|
201
|
+
// Customization label
|
|
202
|
+
woocommerce_wp_text_input(array(
|
|
203
|
+
'id' => '_customization_label',
|
|
204
|
+
'label' => __('Customization Label', 'product-customizer'),
|
|
205
|
+
'placeholder' => __('Enter your custom text', 'product-customizer'),
|
|
206
|
+
'desc_tip' => true,
|
|
207
|
+
'description' => __('Label shown to customers for the custom field.', 'product-customizer'),
|
|
208
|
+
));
|
|
209
|
+
|
|
210
|
+
// Max characters
|
|
211
|
+
woocommerce_wp_text_input(array(
|
|
212
|
+
'id' => '_customization_max_chars',
|
|
213
|
+
'label' => __('Max Characters', 'product-customizer'),
|
|
214
|
+
'placeholder' => '50',
|
|
215
|
+
'type' => 'number',
|
|
216
|
+
'desc_tip' => true,
|
|
217
|
+
'description' => __('Maximum number of characters allowed.', 'product-customizer'),
|
|
218
|
+
'custom_attributes' => array(
|
|
219
|
+
'min' => '1',
|
|
220
|
+
'step' => '1',
|
|
221
|
+
),
|
|
222
|
+
));
|
|
223
|
+
|
|
224
|
+
// Additional price for customization
|
|
225
|
+
woocommerce_wp_text_input(array(
|
|
226
|
+
'id' => '_customization_price',
|
|
227
|
+
'label' => __('Customization Price', 'product-customizer') . ' (' . get_woocommerce_currency_symbol() . ')',
|
|
228
|
+
'placeholder' => '0.00',
|
|
229
|
+
'type' => 'number',
|
|
230
|
+
'desc_tip' => true,
|
|
231
|
+
'description' => __('Additional price for customization.', 'product-customizer'),
|
|
232
|
+
'custom_attributes' => array(
|
|
233
|
+
'min' => '0',
|
|
234
|
+
'step' => '0.01',
|
|
235
|
+
),
|
|
236
|
+
));
|
|
237
|
+
|
|
238
|
+
echo '</div>';
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Save custom product fields
|
|
243
|
+
*
|
|
244
|
+
* @param int $post_id Product ID.
|
|
245
|
+
*/
|
|
246
|
+
public function save_product_fields($post_id) {
|
|
247
|
+
$enable_customization = isset($_POST['_enable_customization']) ? 'yes' : 'no';
|
|
248
|
+
update_post_meta($post_id, '_enable_customization', $enable_customization);
|
|
249
|
+
|
|
250
|
+
if (isset($_POST['_customization_label'])) {
|
|
251
|
+
update_post_meta($post_id, '_customization_label', sanitize_text_field($_POST['_customization_label']));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (isset($_POST['_customization_max_chars'])) {
|
|
255
|
+
update_post_meta($post_id, '_customization_max_chars', absint($_POST['_customization_max_chars']));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (isset($_POST['_customization_price'])) {
|
|
259
|
+
update_post_meta($post_id, '_customization_price', floatval($_POST['_customization_price']));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Display custom fields on product page
|
|
265
|
+
*/
|
|
266
|
+
public function display_custom_fields() {
|
|
267
|
+
global $product;
|
|
268
|
+
|
|
269
|
+
$enable_customization = get_post_meta($product->get_id(), '_enable_customization', true);
|
|
270
|
+
|
|
271
|
+
if ($enable_customization !== 'yes') {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
$label = get_post_meta($product->get_id(), '_customization_label', true);
|
|
276
|
+
$max_chars = get_post_meta($product->get_id(), '_customization_max_chars', true);
|
|
277
|
+
$price = get_post_meta($product->get_id(), '_customization_price', true);
|
|
278
|
+
|
|
279
|
+
$label = $label ?: __('Custom Text', 'product-customizer');
|
|
280
|
+
$max_chars = $max_chars ?: 50;
|
|
281
|
+
|
|
282
|
+
wc_get_template(
|
|
283
|
+
'product-fields.php',
|
|
284
|
+
array(
|
|
285
|
+
'label' => $label,
|
|
286
|
+
'max_chars' => $max_chars,
|
|
287
|
+
'price' => $price,
|
|
288
|
+
),
|
|
289
|
+
'',
|
|
290
|
+
PC_PLUGIN_DIR . 'templates/'
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Cart Handler Class
|
|
299
|
+
|
|
300
|
+
### File: `includes/class-cart-handler.php`
|
|
301
|
+
|
|
302
|
+
```php
|
|
303
|
+
<?php
|
|
304
|
+
/**
|
|
305
|
+
* Cart Handler
|
|
306
|
+
*
|
|
307
|
+
* @package Product_Customizer
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
class PC_Cart_Handler {
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Constructor
|
|
314
|
+
*/
|
|
315
|
+
public function __construct() {
|
|
316
|
+
// Add custom data to cart item
|
|
317
|
+
add_filter('woocommerce_add_cart_item_data', array($this, 'add_cart_item_data'), 10, 3);
|
|
318
|
+
|
|
319
|
+
// Display custom data in cart
|
|
320
|
+
add_filter('woocommerce_get_item_data', array($this, 'display_cart_item_data'), 10, 2);
|
|
321
|
+
|
|
322
|
+
// Adjust cart item price
|
|
323
|
+
add_action('woocommerce_before_calculate_totals', array($this, 'adjust_cart_item_price'));
|
|
324
|
+
|
|
325
|
+
// Validate custom field
|
|
326
|
+
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_custom_field'), 10, 3);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Add custom data to cart item
|
|
331
|
+
*
|
|
332
|
+
* @param array $cart_item_data Cart item data.
|
|
333
|
+
* @param int $product_id Product ID.
|
|
334
|
+
* @param int $variation_id Variation ID.
|
|
335
|
+
* @return array Modified cart item data.
|
|
336
|
+
*/
|
|
337
|
+
public function add_cart_item_data($cart_item_data, $product_id, $variation_id) {
|
|
338
|
+
if (isset($_POST['custom_text']) && !empty($_POST['custom_text'])) {
|
|
339
|
+
$cart_item_data['custom_text'] = sanitize_text_field($_POST['custom_text']);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return $cart_item_data;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Display custom data in cart
|
|
347
|
+
*
|
|
348
|
+
* @param array $item_data Item data.
|
|
349
|
+
* @param array $cart_item Cart item.
|
|
350
|
+
* @return array Modified item data.
|
|
351
|
+
*/
|
|
352
|
+
public function display_cart_item_data($item_data, $cart_item) {
|
|
353
|
+
if (isset($cart_item['custom_text'])) {
|
|
354
|
+
$item_data[] = array(
|
|
355
|
+
'key' => __('Custom Text', 'product-customizer'),
|
|
356
|
+
'value' => wc_clean($cart_item['custom_text']),
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return $item_data;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Adjust cart item price
|
|
365
|
+
*
|
|
366
|
+
* @param WC_Cart $cart Cart object.
|
|
367
|
+
*/
|
|
368
|
+
public function adjust_cart_item_price($cart) {
|
|
369
|
+
if (is_admin() && !defined('DOING_AJAX')) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
|
374
|
+
if (isset($cart_item['custom_text'])) {
|
|
375
|
+
$product_id = $cart_item['product_id'];
|
|
376
|
+
$customization_price = get_post_meta($product_id, '_customization_price', true);
|
|
377
|
+
|
|
378
|
+
if ($customization_price > 0) {
|
|
379
|
+
$new_price = $cart_item['data']->get_price() + floatval($customization_price);
|
|
380
|
+
$cart_item['data']->set_price($new_price);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Validate custom field
|
|
388
|
+
*
|
|
389
|
+
* @param bool $passed Validation status.
|
|
390
|
+
* @param int $product_id Product ID.
|
|
391
|
+
* @param int $quantity Quantity.
|
|
392
|
+
* @return bool Validation status.
|
|
393
|
+
*/
|
|
394
|
+
public function validate_custom_field($passed, $product_id, $quantity) {
|
|
395
|
+
$enable_customization = get_post_meta($product_id, '_enable_customization', true);
|
|
396
|
+
|
|
397
|
+
if ($enable_customization !== 'yes') {
|
|
398
|
+
return $passed;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (!isset($_POST['custom_text']) || empty($_POST['custom_text'])) {
|
|
402
|
+
wc_add_notice(__('Please enter custom text.', 'product-customizer'), 'error');
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
$max_chars = get_post_meta($product_id, '_customization_max_chars', true);
|
|
407
|
+
$max_chars = $max_chars ?: 50;
|
|
408
|
+
|
|
409
|
+
if (strlen($_POST['custom_text']) > $max_chars) {
|
|
410
|
+
wc_add_notice(
|
|
411
|
+
sprintf(
|
|
412
|
+
__('Custom text must be %d characters or less.', 'product-customizer'),
|
|
413
|
+
$max_chars
|
|
414
|
+
),
|
|
415
|
+
'error'
|
|
416
|
+
);
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return $passed;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Order Handler Class
|
|
428
|
+
|
|
429
|
+
### File: `includes/class-order-handler.php`
|
|
430
|
+
|
|
431
|
+
```php
|
|
432
|
+
<?php
|
|
433
|
+
/**
|
|
434
|
+
* Order Handler
|
|
435
|
+
*
|
|
436
|
+
* @package Product_Customizer
|
|
437
|
+
*/
|
|
438
|
+
|
|
439
|
+
class PC_Order_Handler {
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Constructor
|
|
443
|
+
*/
|
|
444
|
+
public function __construct() {
|
|
445
|
+
// Save custom data to order item meta
|
|
446
|
+
add_action('woocommerce_checkout_create_order_line_item', array($this, 'save_order_item_meta'), 10, 4);
|
|
447
|
+
|
|
448
|
+
// Display custom data in admin order
|
|
449
|
+
add_action('woocommerce_before_order_itemmeta', array($this, 'display_order_item_meta'), 10, 3);
|
|
450
|
+
|
|
451
|
+
// Display custom data in emails
|
|
452
|
+
add_filter('woocommerce_order_item_display_meta_key', array($this, 'format_meta_key'), 10, 3);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Save custom data to order item meta
|
|
457
|
+
*
|
|
458
|
+
* @param WC_Order_Item_Product $item Order item.
|
|
459
|
+
* @param string $cart_item_key Cart item key.
|
|
460
|
+
* @param array $values Cart item values.
|
|
461
|
+
* @param WC_Order $order Order object.
|
|
462
|
+
*/
|
|
463
|
+
public function save_order_item_meta($item, $cart_item_key, $values, $order) {
|
|
464
|
+
if (isset($values['custom_text'])) {
|
|
465
|
+
$item->add_meta_data(__('Custom Text', 'product-customizer'), $values['custom_text'], true);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Display custom data in admin order
|
|
471
|
+
*
|
|
472
|
+
* @param int $item_id Order item ID.
|
|
473
|
+
* @param WC_Order_Item $item Order item.
|
|
474
|
+
* @param WC_Product $product Product object.
|
|
475
|
+
*/
|
|
476
|
+
public function display_order_item_meta($item_id, $item, $product) {
|
|
477
|
+
$custom_text = $item->get_meta('Custom Text');
|
|
478
|
+
|
|
479
|
+
if ($custom_text) {
|
|
480
|
+
echo '<div class="wc-order-item-custom-text">';
|
|
481
|
+
echo '<strong>' . __('Custom Text:', 'product-customizer') . '</strong> ';
|
|
482
|
+
echo esc_html($custom_text);
|
|
483
|
+
echo '</div>';
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Format meta key for display
|
|
489
|
+
*
|
|
490
|
+
* @param string $display_key Meta key.
|
|
491
|
+
* @param WC_Meta_Data $meta Meta data object.
|
|
492
|
+
* @param WC_Order_Item $item Order item.
|
|
493
|
+
* @return string Formatted meta key.
|
|
494
|
+
*/
|
|
495
|
+
public function format_meta_key($display_key, $meta, $item) {
|
|
496
|
+
if ($meta->key === 'Custom Text') {
|
|
497
|
+
return __('Custom Text', 'product-customizer');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return $display_key;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Frontend Template
|
|
508
|
+
|
|
509
|
+
### File: `templates/product-fields.php`
|
|
510
|
+
|
|
511
|
+
```php
|
|
512
|
+
<?php
|
|
513
|
+
/**
|
|
514
|
+
* Product Custom Fields Template
|
|
515
|
+
*
|
|
516
|
+
* @package Product_Customizer
|
|
517
|
+
*/
|
|
518
|
+
|
|
519
|
+
if (!defined('ABSPATH')) {
|
|
520
|
+
exit;
|
|
521
|
+
}
|
|
522
|
+
?>
|
|
523
|
+
|
|
524
|
+
<div class="product-customizer-fields">
|
|
525
|
+
<div class="custom-field-wrapper">
|
|
526
|
+
<label for="custom_text">
|
|
527
|
+
<?php echo esc_html($label); ?>
|
|
528
|
+
<?php if ($price > 0) : ?>
|
|
529
|
+
<span class="custom-field-price">
|
|
530
|
+
(+<?php echo wc_price($price); ?>)
|
|
531
|
+
</span>
|
|
532
|
+
<?php endif; ?>
|
|
533
|
+
</label>
|
|
534
|
+
|
|
535
|
+
<input
|
|
536
|
+
type="text"
|
|
537
|
+
id="custom_text"
|
|
538
|
+
name="custom_text"
|
|
539
|
+
class="custom-text-input"
|
|
540
|
+
maxlength="<?php echo esc_attr($max_chars); ?>"
|
|
541
|
+
placeholder="<?php echo esc_attr($label); ?>"
|
|
542
|
+
required
|
|
543
|
+
/>
|
|
544
|
+
|
|
545
|
+
<span class="char-counter">
|
|
546
|
+
<span class="current-chars">0</span> / <?php echo esc_html($max_chars); ?> <?php _e('characters', 'product-customizer'); ?>
|
|
547
|
+
</span>
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
|
|
551
|
+
<style>
|
|
552
|
+
.product-customizer-fields {
|
|
553
|
+
margin: 20px 0;
|
|
554
|
+
padding: 15px;
|
|
555
|
+
background: #f9f9f9;
|
|
556
|
+
border: 1px solid #ddd;
|
|
557
|
+
border-radius: 4px;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.custom-field-wrapper label {
|
|
561
|
+
display: block;
|
|
562
|
+
margin-bottom: 8px;
|
|
563
|
+
font-weight: 600;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.custom-field-price {
|
|
567
|
+
color: #77a464;
|
|
568
|
+
font-weight: normal;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.custom-text-input {
|
|
572
|
+
width: 100%;
|
|
573
|
+
padding: 10px;
|
|
574
|
+
border: 1px solid #ddd;
|
|
575
|
+
border-radius: 4px;
|
|
576
|
+
font-size: 14px;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.char-counter {
|
|
580
|
+
display: block;
|
|
581
|
+
margin-top: 5px;
|
|
582
|
+
font-size: 12px;
|
|
583
|
+
color: #666;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.char-counter .current-chars {
|
|
587
|
+
font-weight: 600;
|
|
588
|
+
}
|
|
589
|
+
</style>
|
|
590
|
+
|
|
591
|
+
<script>
|
|
592
|
+
(function() {
|
|
593
|
+
'use strict';
|
|
594
|
+
|
|
595
|
+
const input = document.getElementById('custom_text');
|
|
596
|
+
const counter = document.querySelector('.current-chars');
|
|
597
|
+
|
|
598
|
+
if (input && counter) {
|
|
599
|
+
input.addEventListener('input', function() {
|
|
600
|
+
counter.textContent = this.value.length;
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
})();
|
|
604
|
+
</script>
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Key Features Demonstrated
|
|
610
|
+
|
|
611
|
+
### 1. **Admin Product Fields**
|
|
612
|
+
- ✅ Custom checkbox field
|
|
613
|
+
- ✅ Text input fields
|
|
614
|
+
- ✅ Number input fields
|
|
615
|
+
- ✅ Field validation
|
|
616
|
+
- ✅ Meta data storage
|
|
617
|
+
|
|
618
|
+
### 2. **Frontend Display**
|
|
619
|
+
- ✅ Custom template
|
|
620
|
+
- ✅ Character counter
|
|
621
|
+
- ✅ Price display
|
|
622
|
+
- ✅ Inline styles and scripts
|
|
623
|
+
|
|
624
|
+
### 3. **Cart Integration**
|
|
625
|
+
- ✅ Add custom data to cart
|
|
626
|
+
- ✅ Display in cart
|
|
627
|
+
- ✅ Price adjustment
|
|
628
|
+
- ✅ Validation
|
|
629
|
+
|
|
630
|
+
### 4. **Order Management**
|
|
631
|
+
- ✅ Save to order item meta
|
|
632
|
+
- ✅ Display in admin order
|
|
633
|
+
- ✅ Display in emails
|
|
634
|
+
- ✅ HPOS compatible
|
|
635
|
+
|
|
636
|
+
### 5. **WooCommerce Best Practices**
|
|
637
|
+
- ✅ HPOS compatibility declaration
|
|
638
|
+
- ✅ WooCommerce dependency check
|
|
639
|
+
- ✅ Proper hooks and filters
|
|
640
|
+
- ✅ Sanitization and escaping
|
|
641
|
+
- ✅ Translation ready
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## Usage Examples
|
|
646
|
+
|
|
647
|
+
### Enable Customization for a Product
|
|
648
|
+
|
|
649
|
+
1. Edit product in WordPress admin
|
|
650
|
+
2. Scroll to "Product Data" meta box
|
|
651
|
+
3. Check "Enable Customization"
|
|
652
|
+
4. Set customization label (e.g., "Engraving Text")
|
|
653
|
+
5. Set max characters (e.g., 50)
|
|
654
|
+
6. Set additional price (e.g., 5.00)
|
|
655
|
+
7. Save product
|
|
656
|
+
|
|
657
|
+
### Customer Experience
|
|
658
|
+
|
|
659
|
+
1. Customer views product page
|
|
660
|
+
2. Sees custom text field with character counter
|
|
661
|
+
3. Enters custom text (validated on add to cart)
|
|
662
|
+
4. Adds to cart (price adjusted if customization price set)
|
|
663
|
+
5. Custom text shown in cart, checkout, and order
|
|
664
|
+
|
|
665
|
+
### Admin Order View
|
|
666
|
+
|
|
667
|
+
1. View order in admin
|
|
668
|
+
2. Custom text displayed with order item
|
|
669
|
+
3. Visible in order emails
|
|
670
|
+
4. Stored in order item meta
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## Extending the Example
|
|
675
|
+
|
|
676
|
+
### Add More Field Types
|
|
677
|
+
|
|
678
|
+
```php
|
|
679
|
+
// Add select field
|
|
680
|
+
woocommerce_wp_select(array(
|
|
681
|
+
'id' => '_customization_type',
|
|
682
|
+
'label' => __('Customization Type', 'product-customizer'),
|
|
683
|
+
'options' => array(
|
|
684
|
+
'engraving' => __('Engraving', 'product-customizer'),
|
|
685
|
+
'printing' => __('Printing', 'product-customizer'),
|
|
686
|
+
'embossing' => __('Embossing', 'product-customizer'),
|
|
687
|
+
),
|
|
688
|
+
));
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
### Add Image Upload
|
|
692
|
+
|
|
693
|
+
```php
|
|
694
|
+
// Add image upload field
|
|
695
|
+
add_action('woocommerce_before_add_to_cart_button', function() {
|
|
696
|
+
?>
|
|
697
|
+
<div class="custom-image-upload">
|
|
698
|
+
<label><?php _e('Upload Custom Image', 'product-customizer'); ?></label>
|
|
699
|
+
<input type="file" name="custom_image" accept="image/*" />
|
|
700
|
+
</div>
|
|
701
|
+
<?php
|
|
702
|
+
});
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Add Preview
|
|
706
|
+
|
|
707
|
+
```php
|
|
708
|
+
// Add live preview
|
|
709
|
+
add_action('woocommerce_before_add_to_cart_button', function() {
|
|
710
|
+
?>
|
|
711
|
+
<div class="customization-preview">
|
|
712
|
+
<h4><?php _e('Preview', 'product-customizer'); ?></h4>
|
|
713
|
+
<div id="preview-text"></div>
|
|
714
|
+
</div>
|
|
715
|
+
<script>
|
|
716
|
+
document.getElementById('custom_text').addEventListener('input', function() {
|
|
717
|
+
document.getElementById('preview-text').textContent = this.value;
|
|
718
|
+
});
|
|
719
|
+
</script>
|
|
720
|
+
<?php
|
|
721
|
+
});
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## Testing Checklist
|
|
727
|
+
|
|
728
|
+
- [ ] Product fields save correctly in admin
|
|
729
|
+
- [ ] Custom fields display on product page
|
|
730
|
+
- [ ] Validation works (required, max length)
|
|
731
|
+
- [ ] Custom data added to cart
|
|
732
|
+
- [ ] Price adjustment works
|
|
733
|
+
- [ ] Custom data saved to order
|
|
734
|
+
- [ ] Custom data displays in admin order
|
|
735
|
+
- [ ] Custom data displays in emails
|
|
736
|
+
- [ ] HPOS compatibility verified
|
|
737
|
+
- [ ] Translation strings work
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## Best Practices Demonstrated
|
|
742
|
+
|
|
743
|
+
1. **HPOS Compatibility** - Declared compatibility with custom order tables
|
|
744
|
+
2. **WooCommerce Dependency** - Check for WooCommerce before activation
|
|
745
|
+
3. **Proper Hooks** - Use WooCommerce hooks and filters
|
|
746
|
+
4. **Sanitization** - All input sanitized
|
|
747
|
+
5. **Escaping** - All output escaped
|
|
748
|
+
6. **Translation Ready** - All strings translatable
|
|
749
|
+
7. **Template System** - Use WooCommerce template system
|
|
750
|
+
8. **Meta Data** - Proper meta data storage and retrieval
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## Next Steps
|
|
755
|
+
|
|
756
|
+
1. Add more field types (select, checkbox, radio, file upload)
|
|
757
|
+
2. Add conditional logic (show/hide fields based on product type)
|
|
758
|
+
3. Add preview functionality
|
|
759
|
+
4. Add admin settings page
|
|
760
|
+
5. Add bulk editing for multiple products
|
|
761
|
+
6. Add import/export for customization settings
|
|
762
|
+
7. Add REST API endpoints for customization data
|
|
763
|
+
|