1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Attributes Page |
4
|
|
|
* |
5
|
|
|
* The attributes section lets users add custom attributes to assign to products - they can also be used in the layered nav widget. |
6
|
|
|
* |
7
|
|
|
* @author WooThemes |
8
|
|
|
* @category Admin |
9
|
|
|
* @package WooCommerce/Admin |
10
|
|
|
* @version 2.3.0 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
14
|
|
|
exit; // Exit if accessed directly |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* WC_Admin_Attributes Class |
19
|
|
|
*/ |
20
|
|
|
class WC_Admin_Attributes { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Handles output of the attributes page in admin. |
24
|
|
|
* |
25
|
|
|
* Shows the created attributes and lets you add new ones or edit existing ones. |
26
|
|
|
* The added attributes are stored in the database and can be used for layered navigation. |
27
|
|
|
*/ |
28
|
|
|
public static function output() { |
29
|
|
|
$result = ''; |
30
|
|
|
$action = ''; |
31
|
|
|
|
32
|
|
|
// Action to perform: add, edit, delete or none |
33
|
|
|
if ( ! empty( $_POST['add_new_attribute'] ) ) { |
34
|
|
|
$action = 'add'; |
35
|
|
|
} elseif ( ! empty( $_POST['save_attribute'] ) && ! empty( $_GET['edit'] ) ) { |
36
|
|
|
$action = 'edit'; |
37
|
|
|
} elseif ( ! empty( $_GET['delete'] ) ) { |
38
|
|
|
$action = 'delete'; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
switch ( $action ) { |
42
|
|
|
case 'add' : |
43
|
|
|
$result = self::process_add_attribute(); |
44
|
|
|
break; |
45
|
|
|
case 'edit' : |
46
|
|
|
$result = self::process_edit_attribute(); |
47
|
|
|
break; |
48
|
|
|
case 'delete' : |
49
|
|
|
$result = self::process_delete_attribute(); |
50
|
|
|
break; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
if ( is_wp_error( $result ) ) { |
54
|
|
|
echo '<div id="woocommerce_errors" class="error"><p>' . $result->get_error_message() . '</p></div>'; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
// Show admin interface |
58
|
|
|
if ( ! empty( $_GET['edit'] ) ) { |
59
|
|
|
self::edit_attribute(); |
60
|
|
|
} else { |
61
|
|
|
self::add_attribute(); |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Get and sanitize posted attribute data. |
67
|
|
|
* @return array |
68
|
|
|
*/ |
69
|
|
|
private static function get_posted_attribute() { |
70
|
|
|
$attribute = array( |
71
|
|
|
'attribute_label' => isset( $_POST['attribute_label'] ) ? wc_clean( stripslashes( $_POST['attribute_label'] ) ) : '', |
72
|
|
|
'attribute_name' => isset( $_POST['attribute_name'] ) ? wc_sanitize_taxonomy_name( stripslashes( $_POST['attribute_name'] ) ) : '', |
73
|
|
|
'attribute_type' => isset( $_POST['attribute_type'] ) ? wc_clean( $_POST['attribute_type'] ) : 'select', |
74
|
|
|
'attribute_orderby' => isset( $_POST['attribute_orderby'] ) ? wc_clean( $_POST['attribute_orderby'] ) : '', |
75
|
|
|
'attribute_public' => isset( $_POST['attribute_public'] ) ? 1 : 0, |
76
|
|
|
'attribute_description' => isset( $_POST['attribute_description'] ) ? wc_clean( stripslashes( $_POST['attribute_description'] ) ) : '', |
77
|
|
|
'attribute_thumbnail_id' => isset( $_POST['attribute_thumbnail_id'] ) ? absint( $_POST['attribute_thumbnail_id'] ) : '' |
78
|
|
|
); |
79
|
|
|
|
80
|
|
|
if ( empty( $attribute['attribute_type'] ) ) { |
81
|
|
|
$attribute['attribute_type'] = 'select'; |
82
|
|
|
} |
83
|
|
|
if ( empty( $attribute['attribute_label'] ) ) { |
84
|
|
|
$attribute['attribute_label'] = ucfirst( $attribute['attribute_name'] ); |
85
|
|
|
} |
86
|
|
|
if ( empty( $attribute['attribute_name'] ) ) { |
87
|
|
|
$attribute['attribute_name'] = wc_sanitize_taxonomy_name( $attribute['attribute_label'] ); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return $attribute; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* See if an attribute name is valid. |
95
|
|
|
* @param string $attribute_name |
96
|
|
|
* @return bool|WP_error result |
97
|
|
|
*/ |
98
|
|
|
private static function valid_attribute_name( $attribute_name ) { |
99
|
|
|
if ( strlen( $attribute_name ) >= 28 ) { |
100
|
|
|
return new WP_Error( 'error', sprintf( __( 'Slug "%s" is too long (28 characters max). Shorten it, please.', 'woocommerce' ), sanitize_title( $attribute_name ) ) ); |
101
|
|
|
} elseif ( wc_check_if_attribute_name_is_reserved( $attribute_name ) ) { |
102
|
|
|
return new WP_Error( 'error', sprintf( __( 'Slug "%s" is not allowed because it is a reserved term. Change it, please.', 'woocommerce' ), sanitize_title( $attribute_name ) ) ); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
return true; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Add an attribute. |
110
|
|
|
* @return bool|WP_Error |
111
|
|
|
*/ |
112
|
|
|
private static function process_add_attribute() { |
113
|
|
|
global $wpdb; |
114
|
|
|
check_admin_referer( 'woocommerce-add-new_attribute' ); |
115
|
|
|
|
116
|
|
|
$attribute = self::get_posted_attribute(); |
117
|
|
|
|
118
|
|
|
if ( empty( $attribute['attribute_name'] ) || empty( $attribute['attribute_label'] ) ) { |
119
|
|
|
return new WP_Error( 'error', __( 'Please, provide an attribute name and slug.', 'woocommerce' ) ); |
120
|
|
|
} elseif ( ( $valid_attribute_name = self::valid_attribute_name( $attribute['attribute_name'] ) ) && is_wp_error( $valid_attribute_name ) ) { |
121
|
|
|
return $valid_attribute_name; |
122
|
|
|
} elseif ( taxonomy_exists( wc_attribute_taxonomy_name( $attribute['attribute_name'] ) ) ) { |
123
|
|
|
return new WP_Error( 'error', sprintf( __( 'Slug "%s" is already in use. Change it, please.', 'woocommerce' ), sanitize_title( $attribute['attribute_name'] ) ) ); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute ); |
127
|
|
|
|
128
|
|
|
do_action( 'woocommerce_attribute_added', $wpdb->insert_id, $attribute ); |
129
|
|
|
|
130
|
|
|
flush_rewrite_rules(); |
131
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
132
|
|
|
|
133
|
|
|
return true; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Edit an attribute. |
138
|
|
|
* @return bool|WP_Error |
139
|
|
|
*/ |
140
|
|
|
private static function process_edit_attribute() { |
141
|
|
|
global $wpdb; |
142
|
|
|
$attribute_id = absint( $_GET['edit'] ); |
143
|
|
|
check_admin_referer( 'woocommerce-save-attribute_' . $attribute_id ); |
144
|
|
|
|
145
|
|
|
$attribute = self::get_posted_attribute(); |
146
|
|
|
|
147
|
|
|
if ( empty( $attribute['attribute_name'] ) || empty( $attribute['attribute_label'] ) ) { |
148
|
|
|
return new WP_Error( 'error', __( 'Please, provide an attribute name and slug.', 'woocommerce' ) ); |
149
|
|
|
} elseif ( ( $valid_attribute_name = self::valid_attribute_name( $attribute['attribute_name'] ) ) && is_wp_error( $valid_attribute_name ) ) { |
150
|
|
|
return $valid_attribute_name; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
$taxonomy_exists = taxonomy_exists( wc_attribute_taxonomy_name( $attribute['attribute_name'] ) ); |
154
|
|
|
$old_attribute_name = $wpdb->get_var( "SELECT attribute_name FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_id = $attribute_id" ); |
155
|
|
|
if ( $old_attribute_name != $attribute['attribute_name'] && wc_sanitize_taxonomy_name( $old_attribute_name ) != $attribute['attribute_name'] && $taxonomy_exists ) { |
156
|
|
|
return new WP_Error( 'error', sprintf( __( 'Slug "%s" is already in use. Change it, please.', 'woocommerce' ), sanitize_title( $attribute['attribute_name'] ) ) ); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
$wpdb->update( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute, array( 'attribute_id' => $attribute_id ) ); |
160
|
|
|
|
161
|
|
|
do_action( 'woocommerce_attribute_updated', $attribute_id, $attribute, $old_attribute_name ); |
162
|
|
|
|
163
|
|
|
if ( $old_attribute_name != $attribute['attribute_name'] && ! empty( $old_attribute_name ) ) { |
164
|
|
|
// Update taxonomies in the wp term taxonomy table |
165
|
|
|
$wpdb->update( |
166
|
|
|
$wpdb->term_taxonomy, |
167
|
|
|
array( 'taxonomy' => wc_attribute_taxonomy_name( $attribute['attribute_name'] ) ), |
168
|
|
|
array( 'taxonomy' => 'pa_' . $old_attribute_name ) |
169
|
|
|
); |
170
|
|
|
|
171
|
|
|
// Update taxonomy ordering term meta |
172
|
|
|
if ( get_option( 'db_version' ) < 34370 ) { |
173
|
|
|
$wpdb->update( |
174
|
|
|
$wpdb->prefix . 'woocommerce_termmeta', |
175
|
|
|
array( 'meta_key' => 'order_pa_' . sanitize_title( $attribute['attribute_name'] ) ), |
176
|
|
|
array( 'meta_key' => 'order_pa_' . sanitize_title( $old_attribute_name ) ) |
177
|
|
|
); |
178
|
|
|
} else { |
179
|
|
|
$wpdb->update( |
180
|
|
|
$wpdb->termmeta, |
181
|
|
|
array( 'meta_key' => 'order_pa_' . sanitize_title( $attribute['attribute_name'] ) ), |
182
|
|
|
array( 'meta_key' => 'order_pa_' . sanitize_title( $old_attribute_name ) ) |
183
|
|
|
); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
// Update product attributes which use this taxonomy |
187
|
|
|
$old_attribute_name_length = strlen( $old_attribute_name ) + 3; |
188
|
|
|
$attribute_name_length = strlen( $attribute['attribute_name'] ) + 3; |
189
|
|
|
|
190
|
|
|
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE( meta_value, %s, %s ) WHERE meta_key = '_product_attributes_ext'", |
191
|
|
|
's:' . $old_attribute_name_length . ':"pa_' . $old_attribute_name . '"', |
192
|
|
|
's:' . $attribute_name_length . ':"pa_' . $attribute['attribute_name'] . '"' |
193
|
|
|
) ); |
194
|
|
|
|
195
|
|
|
// Update variations which use this taxonomy |
196
|
|
|
$wpdb->update( |
197
|
|
|
$wpdb->postmeta, |
198
|
|
|
array( 'meta_key' => 'attribute_pa_' . sanitize_title( $attribute['attribute_name'] ) ), |
199
|
|
|
array( 'meta_key' => 'attribute_pa_' . sanitize_title( $old_attribute_name ) ) |
200
|
|
|
); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
echo '<div class="updated"><p>' . __( 'Attribute updated successfully', 'woocommerce' ) . '</p></div>'; |
204
|
|
|
|
205
|
|
|
flush_rewrite_rules(); |
206
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
207
|
|
|
|
208
|
|
|
return true; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Delete an attribute. |
213
|
|
|
* @return bool |
214
|
|
|
*/ |
215
|
|
|
private static function process_delete_attribute() { |
216
|
|
|
global $wpdb; |
217
|
|
|
|
218
|
|
|
$attribute_id = absint( $_GET['delete'] ); |
219
|
|
|
|
220
|
|
|
check_admin_referer( 'woocommerce-delete-attribute_' . $attribute_id ); |
221
|
|
|
|
222
|
|
|
$attribute_name = $wpdb->get_var( "SELECT attribute_name FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_id = $attribute_id" ); |
223
|
|
|
$taxonomy = wc_attribute_taxonomy_name( $attribute_name ); |
224
|
|
|
|
225
|
|
|
do_action( 'woocommerce_before_attribute_delete', $attribute_id, $attribute_name, $taxonomy ); |
226
|
|
|
|
227
|
|
|
if ( $attribute_name && $wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_id = $attribute_id" ) ) { |
228
|
|
|
if ( taxonomy_exists( $taxonomy ) ) { |
229
|
|
|
$terms = get_terms( $taxonomy, 'orderby=name&hide_empty=0' ); |
230
|
|
|
foreach ( $terms as $term ) { |
231
|
|
|
wp_delete_term( $term->term_id, $taxonomy ); |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
do_action( 'woocommerce_attribute_deleted', $attribute_id, $attribute_name, $taxonomy ); |
236
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
237
|
|
|
return true; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
return false; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Edit Attribute admin panel. |
245
|
|
|
* |
246
|
|
|
* Shows the interface for changing an attributes type between select and text. |
247
|
|
|
*/ |
248
|
|
|
public static function edit_attribute() { |
249
|
|
|
global $wpdb; |
250
|
|
|
|
251
|
|
|
$edit = absint( $_GET['edit'] ); |
252
|
|
|
|
253
|
|
|
$attribute_to_edit = $wpdb->get_row( "SELECT * FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies WHERE attribute_id = '$edit'" ); |
254
|
|
|
|
255
|
|
|
wp_enqueue_media(); |
256
|
|
|
// echo '<pre>'; var_dump($attribute_to_edit); echo '</pre>'; |
|
|
|
|
257
|
|
|
?> |
258
|
|
|
<div class="wrap woocommerce"> |
259
|
|
|
<div class="icon32 icon32-attributes" id="icon-woocommerce"><br/></div> |
260
|
|
|
<h1><?php _e( 'Edit Attribute', 'woocommerce' ) ?></h1> |
261
|
|
|
|
262
|
|
|
<?php |
263
|
|
|
|
264
|
|
|
if ( ! $attribute_to_edit ) { |
265
|
|
|
echo '<div id="woocommerce_errors" class="error"><p>' . __( 'Error: non-existing attribute ID.', 'woocommerce' ) . '</p></div>'; |
266
|
|
|
} else { |
267
|
|
|
$att_type = $attribute_to_edit->attribute_type; |
268
|
|
|
$att_label = $attribute_to_edit->attribute_label; |
269
|
|
|
$att_name = $attribute_to_edit->attribute_name; |
270
|
|
|
$att_desc = $attribute_to_edit->attribute_description; |
271
|
|
|
$att_orderby = $attribute_to_edit->attribute_orderby; |
272
|
|
|
$att_public = $attribute_to_edit->attribute_public; |
273
|
|
|
$thumbnail_id = $attribute_to_edit->attribute_thumbnail_id; |
274
|
|
|
if ( $thumbnail_id ) { |
275
|
|
|
$image = wp_get_attachment_thumb_url( $thumbnail_id ); |
276
|
|
|
} else { |
277
|
|
|
$image = wc_placeholder_img_src(); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
|
281
|
|
|
?> |
282
|
|
|
|
283
|
|
|
<form action="edit.php?post_type=product&page=product_attributes&edit=<?php echo absint( $edit ); ?>" method="post"> |
284
|
|
|
<table class="form-table"> |
285
|
|
|
<tbody> |
286
|
|
|
<tr class="form-field form-required"> |
287
|
|
|
<th scope="row" valign="top"> |
288
|
|
|
<label for="attribute_label"><?php _e( 'Name', 'woocommerce' ); ?></label> |
289
|
|
|
</th> |
290
|
|
|
<td> |
291
|
|
|
<input name="attribute_label" id="attribute_label" type="text" value="<?php echo esc_attr( $att_label ); ?>" /> |
292
|
|
|
<p class="description"><?php _e( 'Name for the attribute (shown on the front-end).', 'woocommerce' ); ?></p> |
293
|
|
|
</td> |
294
|
|
|
</tr> |
295
|
|
|
<tr class="form-field form-required"> |
296
|
|
|
<th scope="row" valign="top"> |
297
|
|
|
<label for="attribute_name"><?php _e( 'Slug', 'woocommerce' ); ?></label> |
298
|
|
|
</th> |
299
|
|
|
<td> |
300
|
|
|
<input name="attribute_name" id="attribute_name" type="text" value="<?php echo esc_attr( $att_name ); ?>" maxlength="28" /> |
301
|
|
|
<p class="description"><?php _e( 'Unique slug/reference for the attribute; must be shorter than 28 characters.', 'woocommerce' ); ?></p> |
302
|
|
|
</td> |
303
|
|
|
</tr> |
304
|
|
|
<tr class="form-field"> |
305
|
|
|
<th scope="row" valign="top"> |
306
|
|
|
<label for="attribute_description"><?php _e( 'Description', 'woocommerce' ); ?></label> |
307
|
|
|
</th> |
308
|
|
|
<td> |
309
|
|
|
<textarea name="attribute_description" id="attribute_description" rows="4"><?php echo esc_attr( $att_desc ); ?></textarea> |
310
|
|
|
<p class="description"><?php _e( 'Description for the attribute, optional.', 'woocommerce' ); ?></p> |
311
|
|
|
</td> |
312
|
|
|
</tr> |
313
|
|
|
<tr class="form-field"> |
314
|
|
|
<th scope="row" valign="top"> |
315
|
|
|
<label><?php _e( 'Attribute Graphic', 'woocommerce' ); ?></label> |
316
|
|
|
</th> |
317
|
|
|
<td> |
318
|
|
|
<div id="attribute_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div> |
319
|
|
|
<div style="line-height: 60px;"> |
320
|
|
|
<input type="hidden" id="attribute_thumbnail_id" name="attribute_thumbnail_id" value="<?php echo $thumbnail_id; ?>" /> |
321
|
|
|
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button> |
322
|
|
|
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button> |
323
|
|
|
</div> |
324
|
|
|
<script type="text/javascript"> |
325
|
|
|
|
326
|
|
|
// Only show the "remove image" button when needed |
327
|
|
|
if ( '0' === jQuery( '#attribute_thumbnail_id' ).val() ) { |
328
|
|
|
jQuery( '.remove_image_button' ).hide(); |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
// Uploading files |
332
|
|
|
var file_frame; |
333
|
|
|
|
334
|
|
|
jQuery( document ).on( 'click', '.upload_image_button', function( event ) { |
335
|
|
|
|
336
|
|
|
event.preventDefault(); |
337
|
|
|
|
338
|
|
|
// If the media frame already exists, reopen it. |
339
|
|
|
if ( file_frame ) { |
340
|
|
|
file_frame.open(); |
341
|
|
|
return; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
// Create the media frame. |
345
|
|
|
file_frame = wp.media.frames.downloadable_file = wp.media({ |
346
|
|
|
title: '<?php _e( "Choose an image", "woocommerce" ); ?>', |
347
|
|
|
button: { |
348
|
|
|
text: '<?php _e( "Use image", "woocommerce" ); ?>' |
349
|
|
|
}, |
350
|
|
|
multiple: false |
351
|
|
|
}); |
352
|
|
|
|
353
|
|
|
// When an image is selected, run a callback. |
354
|
|
|
file_frame.on( 'select', function() { |
355
|
|
|
var attachment = file_frame.state().get( 'selection' ).first().toJSON(); |
356
|
|
|
|
357
|
|
|
jQuery( '#attribute_thumbnail_id' ).val( attachment.id ); |
358
|
|
|
jQuery( '#attribute_thumbnail' ).find( 'img' ).attr( 'src', attachment.url ); |
359
|
|
|
jQuery( '.remove_image_button' ).show(); |
360
|
|
|
}); |
361
|
|
|
|
362
|
|
|
// Finally, open the modal. |
363
|
|
|
file_frame.open(); |
364
|
|
|
}); |
365
|
|
|
|
366
|
|
|
jQuery( document ).on( 'click', '.remove_image_button', function() { |
367
|
|
|
jQuery( '#attribute_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' ); |
368
|
|
|
jQuery( '#attribute_thumbnail_id' ).val( '' ); |
369
|
|
|
jQuery( '.remove_image_button' ).hide(); |
370
|
|
|
return false; |
371
|
|
|
}); |
372
|
|
|
|
373
|
|
|
</script> |
374
|
|
|
<div class="clear"></div> |
375
|
|
|
</td> |
376
|
|
|
</tr> |
377
|
|
|
<tr class="form-field form-required"> |
378
|
|
|
<th scope="row" valign="top"> |
379
|
|
|
<label for="attribute_public"><?php _e( 'Enable Archives?', 'woocommerce' ); ?></label> |
380
|
|
|
</th> |
381
|
|
|
<td> |
382
|
|
|
<input name="attribute_public" id="attribute_public" type="checkbox" value="1" <?php checked( $att_public, 1 ); ?> /> |
383
|
|
|
<p class="description"><?php _e( 'Enable this if you want this attribute to have product archives in your store.', 'woocommerce' ); ?></p> |
384
|
|
|
</td> |
385
|
|
|
</tr> |
386
|
|
|
<tr class="form-field form-required"> |
387
|
|
|
<th scope="row" valign="top"> |
388
|
|
|
<label for="attribute_type"><?php _e( 'Type', 'woocommerce' ); ?></label> |
389
|
|
|
</th> |
390
|
|
|
<td> |
391
|
|
|
<select name="attribute_type" id="attribute_type"> |
392
|
|
|
<?php foreach ( wc_get_attribute_types() as $key => $value ) : ?> |
393
|
|
|
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $att_type, $key ); ?>><?php echo esc_attr( $value ); ?></option> |
394
|
|
|
<?php endforeach; ?> |
395
|
|
|
|
396
|
|
|
<?php |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Deprecated action in favor of product_attributes_type_selector filter. |
400
|
|
|
* |
401
|
|
|
* @deprecated 2.4.0 |
402
|
|
|
*/ |
403
|
|
|
do_action( 'woocommerce_admin_attribute_types' ); |
404
|
|
|
?> |
405
|
|
|
</select> |
406
|
|
|
<p class="description"><?php _e( 'Determines how you select attributes for products. Under admin panel -> products -> product data -> attributes -> values, <strong>Text</strong> allows manual entry whereas <strong>select</strong> allows pre-configured terms in a drop-down list.', 'woocommerce' ); ?></p> |
407
|
|
|
</td> |
408
|
|
|
</tr> |
409
|
|
|
<tr class="form-field form-required"> |
410
|
|
|
<th scope="row" valign="top"> |
411
|
|
|
<label for="attribute_orderby"><?php _e( 'Default sort order', 'woocommerce' ); ?></label> |
412
|
|
|
</th> |
413
|
|
|
<td> |
414
|
|
|
<select name="attribute_orderby" id="attribute_orderby"> |
415
|
|
|
<option value="menu_order" <?php selected( $att_orderby, 'menu_order' ); ?>><?php _e( 'Custom ordering', 'woocommerce' ); ?></option> |
416
|
|
|
<option value="name" <?php selected( $att_orderby, 'name' ); ?>><?php _e( 'Name', 'woocommerce' ); ?></option> |
417
|
|
|
<option value="name_num" <?php selected( $att_orderby, 'name_num' ); ?>><?php _e( 'Name (numeric)', 'woocommerce' ); ?></option> |
418
|
|
|
<option value="id" <?php selected( $att_orderby, 'id' ); ?>><?php _e( 'Term ID', 'woocommerce' ); ?></option> |
419
|
|
|
</select> |
420
|
|
|
<p class="description"><?php _e( 'Determines the sort order of the terms on the frontend shop product pages. If using custom ordering, you can drag and drop the terms in this attribute.', 'woocommerce' ); ?></p> |
421
|
|
|
</td> |
422
|
|
|
</tr> |
423
|
|
|
</tbody> |
424
|
|
|
</table> |
425
|
|
|
<p class="submit"><input type="submit" name="save_attribute" id="submit" class="button-primary" value="<?php esc_attr_e( 'Update', 'woocommerce' ); ?>"></p> |
426
|
|
|
<?php wp_nonce_field( 'woocommerce-save-attribute_' . $edit ); ?> |
427
|
|
|
</form> |
428
|
|
|
<?php } ?> |
429
|
|
|
</div> |
430
|
|
|
<?php |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* Add Attribute admin panel. |
435
|
|
|
* |
436
|
|
|
* Shows the interface for adding new attributes. |
437
|
|
|
*/ |
438
|
|
|
public static function add_attribute() { |
439
|
|
|
wp_enqueue_media(); |
440
|
|
|
?> |
441
|
|
|
<div class="wrap woocommerce"> |
442
|
|
|
<div class="icon32 icon32-attributes" id="icon-woocommerce"><br/></div> |
443
|
|
|
<h1><?php _e( 'Attributes', 'woocommerce' ); ?></h1> |
444
|
|
|
<br class="clear" /> |
445
|
|
|
<div id="col-container"> |
446
|
|
|
<div id="col-right"> |
447
|
|
|
<div class="col-wrap"> |
448
|
|
|
<table class="widefat attributes-table wp-list-table ui-sortable" style="width:100%"> |
449
|
|
|
<thead> |
450
|
|
|
<tr> |
451
|
|
|
<th scope="col"><?php _e( 'Image', 'woocommerce' ); ?></th> |
452
|
|
|
<th scope="col"><?php _e( 'Name', 'woocommerce' ); ?></th> |
453
|
|
|
<th scope="col"><?php _e( 'Slug', 'woocommerce' ); ?></th> |
454
|
|
|
<th scope="col"><?php _e( 'Type', 'woocommerce' ); ?></th> |
455
|
|
|
<th scope="col"><?php _e( 'Order by', 'woocommerce' ); ?></th> |
456
|
|
|
<th scope="col" colspan="2"><?php _e( 'Terms', 'woocommerce' ); ?></th> |
457
|
|
|
</tr> |
458
|
|
|
</thead> |
459
|
|
|
<tbody> |
460
|
|
|
<?php |
461
|
|
|
if ( $attribute_taxonomies = wc_get_attribute_taxonomies() ) : |
462
|
|
|
foreach ( $attribute_taxonomies as $tax ) : |
463
|
|
|
?><tr> |
464
|
|
|
<td> |
465
|
|
|
<?php |
466
|
|
|
$thumbnail_id = $tax->attribute_thumbnail_id; |
467
|
|
|
|
468
|
|
|
if ( $thumbnail_id ) { |
469
|
|
|
$image = wp_get_attachment_thumb_url( $thumbnail_id ); |
470
|
|
|
} else { |
471
|
|
|
$image = wc_placeholder_img_src(); |
472
|
|
|
} |
473
|
|
|
echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr__( 'Thumbnail', 'woocommerce' ) . '" class="wp-post-image" height="48" width="48" />'; |
474
|
|
|
?> |
475
|
|
|
</td> |
476
|
|
|
<td> |
477
|
|
|
<strong><a href="edit-tags.php?taxonomy=<?php echo esc_html( wc_attribute_taxonomy_name( $tax->attribute_name ) ); ?>&post_type=product"><?php echo esc_html( $tax->attribute_label ); ?></a></strong> |
478
|
|
|
|
479
|
|
|
<div class="row-actions"><span class="edit"><a href="<?php echo esc_url( add_query_arg( 'edit', $tax->attribute_id, 'edit.php?post_type=product&page=product_attributes_ext' ) ); ?>"><?php _e( 'Edit', 'woocommerce' ); ?></a> | </span><span class="delete"><a class="delete" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'delete', $tax->attribute_id, 'edit.php?post_type=product&page=product_attributes_ext' ), 'woocommerce-delete-attribute_' . $tax->attribute_id ) ); ?>"><?php _e( 'Delete', 'woocommerce' ); ?></a></span></div> |
480
|
|
|
</td> |
481
|
|
|
<td><?php echo esc_html( $tax->attribute_name ); ?></td> |
482
|
|
|
<td><?php echo esc_html( ucfirst( $tax->attribute_type ) ); ?> <?php echo $tax->attribute_public ? '(' . __( 'Public', 'woocommerce' ) . ')' : ''; ?></td> |
483
|
|
|
<td><?php |
484
|
|
|
switch ( $tax->attribute_orderby ) { |
485
|
|
|
case 'name' : |
486
|
|
|
_e( 'Name', 'woocommerce' ); |
487
|
|
|
break; |
488
|
|
|
case 'name_num' : |
489
|
|
|
_e( 'Name (numeric)', 'woocommerce' ); |
490
|
|
|
break; |
491
|
|
|
case 'id' : |
492
|
|
|
_e( 'Term ID', 'woocommerce' ); |
493
|
|
|
break; |
494
|
|
|
default: |
495
|
|
|
_e( 'Custom ordering', 'woocommerce' ); |
496
|
|
|
break; |
497
|
|
|
} |
498
|
|
|
?></td> |
499
|
|
|
<td class="attribute-terms"><?php |
500
|
|
|
$taxonomy = wc_attribute_taxonomy_name( $tax->attribute_name ); |
501
|
|
|
|
502
|
|
|
if ( taxonomy_exists( $taxonomy ) ) { |
503
|
|
|
$terms = get_terms( $taxonomy, 'hide_empty=0' ); |
504
|
|
|
|
505
|
|
View Code Duplication |
switch ( $tax->attribute_orderby ) { |
|
|
|
|
506
|
|
|
case 'name_num' : |
507
|
|
|
usort( $terms, '_wc_get_product_terms_name_num_usort_callback' ); |
508
|
|
|
break; |
509
|
|
|
case 'parent' : |
510
|
|
|
usort( $terms, '_wc_get_product_terms_parent_usort_callback' ); |
511
|
|
|
break; |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
$terms_string = implode( ', ', wp_list_pluck( $terms, 'name' ) ); |
515
|
|
|
if ( $terms_string ) { |
516
|
|
|
echo $terms_string; |
517
|
|
|
} else { |
518
|
|
|
echo '<span class="na">–</span>'; |
519
|
|
|
} |
520
|
|
|
} else { |
521
|
|
|
echo '<span class="na">–</span>'; |
522
|
|
|
} |
523
|
|
|
?></td> |
524
|
|
|
<td class="attribute-actions"><a href="edit-tags.php?taxonomy=<?php echo esc_html( wc_attribute_taxonomy_name( $tax->attribute_name ) ); ?>&post_type=product" class="button alignright tips configure-terms" data-tip="<?php esc_attr_e( 'Configure terms', 'woocommerce' ); ?>"><?php _e( 'Configure terms', 'woocommerce' ); ?></a></td> |
525
|
|
|
</tr><?php |
526
|
|
|
endforeach; |
527
|
|
|
else : |
528
|
|
|
?><tr><td colspan="6"><?php _e( 'No attributes currently exist.', 'woocommerce' ) ?></td></tr><?php |
529
|
|
|
endif; |
530
|
|
|
?> |
531
|
|
|
</tbody> |
532
|
|
|
</table> |
533
|
|
|
</div> |
534
|
|
|
</div> |
535
|
|
|
<div id="col-left"> |
536
|
|
|
<div class="col-wrap"> |
537
|
|
|
<div class="form-wrap"> |
538
|
|
|
<h2><?php _e( 'Add New Attribute', 'woocommerce' ); ?></h2> |
539
|
|
|
<p><?php _e( 'Attributes let you define extra product data, such as size or colour. You can use these attributes in the shop sidebar using the "layered nav" widgets. Please note: you cannot rename an attribute later on.', 'woocommerce' ); ?></p> |
540
|
|
|
<form action="edit.php?post_type=product&page=product_attributes" method="post"> |
541
|
|
|
<div class="form-field"> |
542
|
|
|
<label for="attribute_label"><?php _e( 'Name', 'woocommerce' ); ?></label> |
543
|
|
|
<input name="attribute_label" id="attribute_label" type="text" value="" /> |
544
|
|
|
<p class="description"><?php _e( 'Name for the attribute (shown on the front-end).', 'woocommerce' ); ?></p> |
545
|
|
|
</div> |
546
|
|
|
|
547
|
|
|
<div class="form-field"> |
548
|
|
|
<label for="attribute_name"><?php _e( 'Slug', 'woocommerce' ); ?></label> |
549
|
|
|
<input name="attribute_name" id="attribute_name" type="text" value="" maxlength="28" /> |
550
|
|
|
<p class="description"><?php _e( 'Unique slug/reference for the attribute; must be shorter than 28 characters.', 'woocommerce' ); ?></p> |
551
|
|
|
</div> |
552
|
|
|
|
553
|
|
|
<div class="form-field"> |
554
|
|
|
<label for="attribute_description"><?php _e( 'Description', 'woocommerce' ); ?></label> |
555
|
|
|
<textarea name="attribute_description" id="attribute_description" value="" rows="4"></textarea> |
556
|
|
|
<p class="description"><?php _e( 'Description for the attribute, optional.', 'woocommerce' ); ?></p> |
557
|
|
|
</div> |
558
|
|
|
|
559
|
|
|
<div class="form-field term-thumbnail-wrap"> |
560
|
|
|
<label><?php _e( 'Attribute Graphic', 'woocommerce' ); ?></label> |
561
|
|
|
<div id="attribute_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( wc_placeholder_img_src() ); ?>" width="60px" height="60px" /></div> |
562
|
|
|
<div style="line-height: 60px;"> |
563
|
|
|
<input type="hidden" id="attribute_thumbnail_id" name="attribute_thumbnail_id" /> |
564
|
|
|
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button> |
565
|
|
|
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button> |
566
|
|
|
</div> |
567
|
|
|
<script type="text/javascript"> |
568
|
|
|
|
569
|
|
|
// Only show the "remove image" button when needed |
570
|
|
|
if ( ! jQuery( '#attribute_thumbnail_id' ).val() ) { |
571
|
|
|
jQuery( '.remove_image_button' ).hide(); |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
// Uploading files |
575
|
|
|
var file_frame; |
576
|
|
|
|
577
|
|
|
jQuery( document ).on( 'click', '.upload_image_button', function( event ) { |
578
|
|
|
|
579
|
|
|
event.preventDefault(); |
580
|
|
|
|
581
|
|
|
// If the media frame already exists, reopen it. |
582
|
|
|
if ( file_frame ) { |
583
|
|
|
file_frame.open(); |
584
|
|
|
return; |
585
|
|
|
} |
586
|
|
|
|
587
|
|
|
// Create the media frame. |
588
|
|
|
file_frame = wp.media.frames.downloadable_file = wp.media({ |
589
|
|
|
title: '<?php _e( "Choose an image", "woocommerce" ); ?>', |
590
|
|
|
button: { |
591
|
|
|
text: '<?php _e( "Use image", "woocommerce" ); ?>' |
592
|
|
|
}, |
593
|
|
|
multiple: false |
594
|
|
|
}); |
595
|
|
|
|
596
|
|
|
// When an image is selected, run a callback. |
597
|
|
|
file_frame.on( 'select', function() { |
598
|
|
|
var attachment = file_frame.state().get( 'selection' ).first().toJSON(); |
599
|
|
|
|
600
|
|
|
jQuery( '#attribute_thumbnail_id' ).val( attachment.id ); |
601
|
|
|
jQuery( '#attribute_thumbnail' ).find( 'img' ).attr( 'src', attachment.thumbnail.url ); |
602
|
|
|
jQuery( '.remove_image_button' ).show(); |
603
|
|
|
}); |
604
|
|
|
|
605
|
|
|
// Finally, open the modal. |
606
|
|
|
file_frame.open(); |
607
|
|
|
}); |
608
|
|
|
|
609
|
|
|
jQuery( document ).on( 'click', '.remove_image_button', function() { |
610
|
|
|
jQuery( '#attribute_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' ); |
611
|
|
|
jQuery( '#attribute_thumbnail_id' ).val( '' ); |
612
|
|
|
jQuery( '.remove_image_button' ).hide(); |
613
|
|
|
return false; |
614
|
|
|
}); |
615
|
|
|
|
616
|
|
|
jQuery( document ).ajaxComplete( function( event, request, options ) { |
617
|
|
|
if ( request && 4 === request.readyState && 200 === request.status |
618
|
|
|
&& options.data && 0 <= options.data.indexOf( 'action=add-tag' ) ) { |
619
|
|
|
|
620
|
|
|
var res = wpAjax.parseAjaxResponse( request.responseXML, 'ajax-response' ); |
621
|
|
|
if ( ! res || res.errors ) { |
622
|
|
|
return; |
623
|
|
|
} |
624
|
|
|
// Clear Thumbnail fields on submit |
625
|
|
|
jQuery( '#attribute_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' ); |
626
|
|
|
jQuery( '#attribute_thumbnail_id' ).val( '' ); |
627
|
|
|
jQuery( '.remove_image_button' ).hide(); |
628
|
|
|
// Clear Display type field on submit |
629
|
|
|
jQuery( '#display_type' ).val( '' ); |
630
|
|
|
return; |
631
|
|
|
} |
632
|
|
|
} ); |
633
|
|
|
|
634
|
|
|
</script> |
635
|
|
|
<div class="clear"></div> |
636
|
|
|
</div> |
637
|
|
|
|
638
|
|
|
<div class="form-field"> |
639
|
|
|
<label for="attribute_public"><input name="attribute_public" id="attribute_public" type="checkbox" value="1" /> <?php _e( 'Enable Archives?', 'woocommerce' ); ?></label> |
640
|
|
|
|
641
|
|
|
<p class="description"><?php _e( 'Enable this if you want this attribute to have product archives in your store.', 'woocommerce' ); ?></p> |
642
|
|
|
</div> |
643
|
|
|
|
644
|
|
|
<div class="form-field"> |
645
|
|
|
<label for="attribute_type"><?php _e( 'Type', 'woocommerce' ); ?></label> |
646
|
|
|
<select name="attribute_type" id="attribute_type"> |
647
|
|
|
<?php foreach ( wc_get_attribute_types() as $key => $value ) : ?> |
648
|
|
|
<option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_attr( $value ); ?></option> |
649
|
|
|
<?php endforeach; ?> |
650
|
|
|
|
651
|
|
|
<?php |
652
|
|
|
|
653
|
|
|
/** |
654
|
|
|
* Deprecated action in favor of product_attributes_type_selector filter. |
655
|
|
|
* |
656
|
|
|
* @deprecated 2.4.0 |
657
|
|
|
*/ |
658
|
|
|
do_action( 'woocommerce_admin_attribute_types' ); |
659
|
|
|
?> |
660
|
|
|
</select> |
661
|
|
|
<p class="description"><?php _e( 'Determines how you select attributes for products. Under admin panel -> products -> product data -> attributes -> values, <strong>Text</strong> allows manual entry whereas <strong>select</strong> allows pre-configured terms in a drop-down list.', 'woocommerce' ); ?></p> |
662
|
|
|
</div> |
663
|
|
|
|
664
|
|
|
<div class="form-field"> |
665
|
|
|
<label for="attribute_orderby"><?php _e( 'Default sort order', 'woocommerce' ); ?></label> |
666
|
|
|
<select name="attribute_orderby" id="attribute_orderby"> |
667
|
|
|
<option value="menu_order"><?php _e( 'Custom ordering', 'woocommerce' ); ?></option> |
668
|
|
|
<option value="name"><?php _e( 'Name', 'woocommerce' ); ?></option> |
669
|
|
|
<option value="name_num"><?php _e( 'Name (numeric)', 'woocommerce' ); ?></option> |
670
|
|
|
<option value="id"><?php _e( 'Term ID', 'woocommerce' ); ?></option> |
671
|
|
|
</select> |
672
|
|
|
<p class="description"><?php _e( 'Determines the sort order of the terms on the frontend shop product pages. If using custom ordering, you can drag and drop the terms in this attribute.', 'woocommerce' ); ?></p> |
673
|
|
|
</div> |
674
|
|
|
|
675
|
|
|
<p class="submit"><input type="submit" name="add_new_attribute" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Attribute', 'woocommerce' ); ?>"></p> |
676
|
|
|
<?php wp_nonce_field( 'woocommerce-add-new_attribute' ); ?> |
677
|
|
|
</form> |
678
|
|
|
</div> |
679
|
|
|
</div> |
680
|
|
|
</div> |
681
|
|
|
</div> |
682
|
|
|
<script type="text/javascript"> |
683
|
|
|
/* <![CDATA[ */ |
684
|
|
|
|
685
|
|
|
jQuery( 'a.delete' ).click( function() { |
686
|
|
|
if ( window.confirm( '<?php _e( "Are you sure you want to delete this attribute?", "woocommerce" ); ?>' ) ) { |
687
|
|
|
return true; |
688
|
|
|
} |
689
|
|
|
return false; |
690
|
|
|
}); |
691
|
|
|
|
692
|
|
|
/* ]]> */ |
693
|
|
|
</script> |
694
|
|
|
</div> |
695
|
|
|
<?php |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
} |
699
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.