PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / admin / class-wc-admin-taxonomies.php
woocommerce / includes / admin Last commit date
helper 2 months ago importers 1 year ago list-tables 1 month ago marketplace-suggestions 11 months ago meta-boxes 1 month ago notes 2 months ago plugin-updates 2 years ago reports 3 months ago settings 1 week ago views 1 month ago class-wc-admin-addons.php 9 months ago class-wc-admin-api-keys-table-list.php 2 years ago class-wc-admin-api-keys.php 11 months ago class-wc-admin-assets.php 1 month ago class-wc-admin-attributes.php 1 month ago class-wc-admin-brands.php 4 months ago class-wc-admin-customize.php 5 years ago class-wc-admin-dashboard-setup.php 1 month ago class-wc-admin-dashboard.php 4 months ago class-wc-admin-duplicate-product.php 5 months ago class-wc-admin-exporters.php 1 year ago class-wc-admin-help.php 2 years ago class-wc-admin-importers.php 11 months ago class-wc-admin-log-table-list.php 4 months ago class-wc-admin-marketplace-promotions.php 4 months ago class-wc-admin-menus.php 1 month ago class-wc-admin-meta-boxes.php 1 month ago class-wc-admin-notices.php 1 month ago class-wc-admin-permalink-settings.php 5 years ago class-wc-admin-pointers.php 3 years ago class-wc-admin-post-types.php 1 year ago class-wc-admin-profile.php 1 year ago class-wc-admin-reports.php 4 months ago class-wc-admin-settings.php 3 months ago class-wc-admin-setup-wizard.php 1 month ago class-wc-admin-status.php 1 year ago class-wc-admin-taxonomies.php 1 month ago class-wc-admin-upload-downloadable-product.php 2 years ago class-wc-admin-webhooks-table-list.php 1 month ago class-wc-admin-webhooks.php 1 month ago class-wc-admin.php 3 months ago wc-admin-functions.php 7 months ago wc-meta-box-functions.php 1 year ago woocommerce-legacy-reports.php 1 year ago
class-wc-admin-taxonomies.php
513 lines
1 <?php
2 /**
3 * Handles taxonomies in admin
4 *
5 * @class WC_Admin_Taxonomies
6 * @version 2.3.10
7 * @package WooCommerce\Admin
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 use Automattic\WooCommerce\Internal\AssignDefaultCategory;
15
16 /**
17 * WC_Admin_Taxonomies class.
18 */
19 class WC_Admin_Taxonomies {
20
21 /**
22 * Class instance.
23 *
24 * @var WC_Admin_Taxonomies instance
25 */
26 protected static $instance = false;
27
28 /**
29 * Default category ID.
30 *
31 * @var int
32 */
33 private $default_cat_id = 0;
34
35 /**
36 * Get class instance
37 */
38 public static function get_instance() {
39 if ( ! self::$instance ) {
40 self::$instance = new self();
41 }
42 return self::$instance;
43 }
44
45 /**
46 * Constructor.
47 */
48 public function __construct() {
49 // Default category ID.
50 $this->default_cat_id = get_option( 'default_product_cat', 0 );
51
52 // Category/term ordering.
53 add_action( 'create_term', array( $this, 'create_term' ), 5, 3 );
54 add_action(
55 'delete_product_cat',
56 function () {
57 wc_get_container()->get( AssignDefaultCategory::class )->schedule_action();
58 }
59 );
60
61 // Add form.
62 add_action( 'product_cat_add_form_fields', array( $this, 'add_category_fields' ) );
63 add_action( 'product_cat_edit_form_fields', array( $this, 'edit_category_fields' ), 10 );
64 add_action( 'created_term', array( $this, 'save_category_fields' ), 10, 3 );
65 add_action( 'edit_term', array( $this, 'save_category_fields' ), 10, 3 );
66
67 // Add columns.
68 add_filter( 'manage_edit-product_cat_columns', array( $this, 'product_cat_columns' ) );
69 add_filter( 'manage_product_cat_custom_column', array( $this, 'product_cat_column' ), 10, 3 );
70
71 // Add row actions.
72 add_filter( 'product_cat_row_actions', array( $this, 'product_cat_row_actions' ), 10, 2 );
73 add_filter( 'admin_init', array( $this, 'handle_product_cat_row_actions' ) );
74
75 // Taxonomy page descriptions.
76 add_action( 'product_cat_pre_add_form', array( $this, 'product_cat_description' ) );
77 add_action( 'after-product_cat-table', array( $this, 'product_cat_notes' ) );
78
79 $attribute_taxonomies = wc_get_attribute_taxonomies();
80
81 if ( ! empty( $attribute_taxonomies ) ) {
82 foreach ( $attribute_taxonomies as $attribute ) {
83 $taxonomy = 'pa_' . $attribute->attribute_name;
84 add_action( $taxonomy . '_pre_add_form', array( $this, 'product_attribute_description' ) );
85 }
86 }
87
88 // Maintain hierarchy of terms.
89 add_filter( 'wp_terms_checklist_args', array( $this, 'disable_checked_ontop' ) );
90
91 // Admin footer scripts for taxonomy screens.
92 add_action( 'admin_footer', array( $this, 'scripts_at_product_cat_screen_footer' ) );
93 }
94
95 /**
96 * Order term when created (put in position 0).
97 *
98 * @param mixed $term_id Term ID.
99 * @param mixed $tt_id Term taxonomy ID.
100 * @param string $taxonomy Taxonomy slug.
101 */
102 public function create_term( $term_id, $tt_id = '', $taxonomy = '' ) {
103 if ( 'product_cat' !== $taxonomy && ! taxonomy_is_product_attribute( $taxonomy ) ) {
104 return;
105 }
106
107 update_term_meta( $term_id, 'order', 0 );
108 }
109
110 /**
111 * When a term is deleted, delete its meta.
112 *
113 * @deprecated 3.6.0 No longer needed.
114 * @param mixed $term_id Term ID.
115 */
116 public function delete_term( $term_id ) {
117 wc_deprecated_function( 'delete_term', '3.6' );
118 }
119
120 /**
121 * Category thumbnail fields.
122 */
123 public function add_category_fields() {
124 ?>
125 <div class="form-field term-display-type-wrap">
126 <label for="display_type"><?php esc_html_e( 'Display type', 'woocommerce' ); ?></label>
127 <select id="display_type" name="display_type" class="postform">
128 <option value=""><?php esc_html_e( 'Default', 'woocommerce' ); ?></option>
129 <option value="products"><?php esc_html_e( 'Products', 'woocommerce' ); ?></option>
130 <option value="subcategories"><?php esc_html_e( 'Subcategories', 'woocommerce' ); ?></option>
131 <option value="both"><?php esc_html_e( 'Both', 'woocommerce' ); ?></option>
132 </select>
133 </div>
134 <div class="form-field term-thumbnail-wrap">
135 <label><?php esc_html_e( 'Thumbnail', 'woocommerce' ); ?></label>
136 <div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( wc_placeholder_img_src() ); ?>" width="60px" height="60px" /></div>
137 <div style="line-height: 60px;">
138 <input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" />
139 <button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'woocommerce' ); ?></button>
140 <button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'woocommerce' ); ?></button>
141 </div>
142 <script type="text/javascript">
143
144 // Only show the "remove image" button when needed
145 if ( ! jQuery( '#product_cat_thumbnail_id' ).val() ) {
146 jQuery( '.remove_image_button' ).hide();
147 }
148
149 // Uploading files
150 var file_frame;
151
152 jQuery( document ).on( 'click', '.upload_image_button', function( event ) {
153
154 event.preventDefault();
155
156 // If the media frame already exists, reopen it.
157 if ( file_frame ) {
158 file_frame.open();
159 return;
160 }
161
162 // Create the media frame.
163 file_frame = wp.media.frames.downloadable_file = wp.media({
164 title: '<?php esc_html_e( 'Choose an image', 'woocommerce' ); ?>',
165 button: {
166 text: '<?php esc_html_e( 'Use image', 'woocommerce' ); ?>'
167 },
168 multiple: false
169 });
170
171 // When an image is selected, run a callback.
172 file_frame.on( 'select', function() {
173 var attachment = file_frame.state().get( 'selection' ).first().toJSON();
174 var attachment_thumbnail = attachment.sizes.thumbnail || attachment.sizes.full;
175
176 jQuery( '#product_cat_thumbnail_id' ).val( attachment.id );
177 jQuery( '#product_cat_thumbnail' ).find( 'img' ).attr( 'src', attachment_thumbnail.url );
178 jQuery( '.remove_image_button' ).show();
179 });
180
181 // Finally, open the modal.
182 file_frame.open();
183 });
184
185 jQuery( document ).on( 'click', '.remove_image_button', function() {
186 jQuery( '#product_cat_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' );
187 jQuery( '#product_cat_thumbnail_id' ).val( '' );
188 jQuery( '.remove_image_button' ).hide();
189 return false;
190 });
191
192 jQuery( document ).ajaxComplete( function( event, request, options ) {
193 if ( request && 4 === request.readyState && 200 === request.status
194 && options.data && 0 <= options.data.indexOf( 'action=add-tag' ) ) {
195
196 var res = wpAjax.parseAjaxResponse( request.responseXML, 'ajax-response' );
197 if ( ! res || res.errors ) {
198 return;
199 }
200 // Clear Thumbnail fields on submit
201 jQuery( '#product_cat_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' );
202 jQuery( '#product_cat_thumbnail_id' ).val( '' );
203 jQuery( '.remove_image_button' ).hide();
204 // Clear Display type field on submit
205 jQuery( '#display_type' ).val( '' );
206 return;
207 }
208 } );
209
210 </script>
211 <div class="clear"></div>
212 </div>
213 <?php
214 }
215
216 /**
217 * Edit category thumbnail field.
218 *
219 * @param mixed $term Term (category) being edited.
220 */
221 public function edit_category_fields( $term ) {
222
223 $display_type = get_term_meta( $term->term_id, 'display_type', true );
224 $thumbnail_id = absint( get_term_meta( $term->term_id, 'thumbnail_id', true ) );
225
226 if ( $thumbnail_id ) {
227 $image = wp_get_attachment_thumb_url( $thumbnail_id );
228 } else {
229 $image = wc_placeholder_img_src();
230 }
231 ?>
232 <tr class="form-field term-display-type-wrap">
233 <th scope="row" valign="top"><label><?php esc_html_e( 'Display type', 'woocommerce' ); ?></label></th>
234 <td>
235 <select id="display_type" name="display_type" class="postform">
236 <option value="" <?php selected( '', $display_type ); ?>><?php esc_html_e( 'Default', 'woocommerce' ); ?></option>
237 <option value="products" <?php selected( 'products', $display_type ); ?>><?php esc_html_e( 'Products', 'woocommerce' ); ?></option>
238 <option value="subcategories" <?php selected( 'subcategories', $display_type ); ?>><?php esc_html_e( 'Subcategories', 'woocommerce' ); ?></option>
239 <option value="both" <?php selected( 'both', $display_type ); ?>><?php esc_html_e( 'Both', 'woocommerce' ); ?></option>
240 </select>
241 </td>
242 </tr>
243 <tr class="form-field term-thumbnail-wrap">
244 <th scope="row" valign="top"><label><?php esc_html_e( 'Thumbnail', 'woocommerce' ); ?></label></th>
245 <td>
246 <div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div>
247 <div style="line-height: 60px;">
248 <input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" value="<?php echo esc_attr( $thumbnail_id ); ?>" />
249 <button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'woocommerce' ); ?></button>
250 <button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'woocommerce' ); ?></button>
251 </div>
252 <script type="text/javascript">
253
254 // Only show the "remove image" button when needed
255 if ( '0' === jQuery( '#product_cat_thumbnail_id' ).val() ) {
256 jQuery( '.remove_image_button' ).hide();
257 }
258
259 // Uploading files
260 var file_frame;
261
262 jQuery( document ).on( 'click', '.upload_image_button', function( event ) {
263
264 event.preventDefault();
265
266 // If the media frame already exists, reopen it.
267 if ( file_frame ) {
268 file_frame.open();
269 return;
270 }
271
272 // Create the media frame.
273 file_frame = wp.media.frames.downloadable_file = wp.media({
274 title: '<?php esc_html_e( 'Choose an image', 'woocommerce' ); ?>',
275 button: {
276 text: '<?php esc_html_e( 'Use image', 'woocommerce' ); ?>'
277 },
278 multiple: false
279 });
280
281 // When an image is selected, run a callback.
282 file_frame.on( 'select', function() {
283 var attachment = file_frame.state().get( 'selection' ).first().toJSON();
284 var attachment_thumbnail = attachment.sizes.thumbnail || attachment.sizes.full;
285
286 jQuery( '#product_cat_thumbnail_id' ).val( attachment.id );
287 jQuery( '#product_cat_thumbnail' ).find( 'img' ).attr( 'src', attachment_thumbnail.url );
288 jQuery( '.remove_image_button' ).show();
289 });
290
291 // Finally, open the modal.
292 file_frame.open();
293 });
294
295 jQuery( document ).on( 'click', '.remove_image_button', function() {
296 jQuery( '#product_cat_thumbnail' ).find( 'img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' );
297 jQuery( '#product_cat_thumbnail_id' ).val( '' );
298 jQuery( '.remove_image_button' ).hide();
299 return false;
300 });
301
302 </script>
303 <div class="clear"></div>
304 </td>
305 </tr>
306 <?php
307 }
308
309 /**
310 * Save category fields
311 *
312 * @param mixed $term_id Term ID being saved.
313 * @param mixed $tt_id Term taxonomy ID.
314 * @param string $taxonomy Taxonomy slug.
315 */
316 public function save_category_fields( $term_id, $tt_id = '', $taxonomy = '' ) {
317 if ( isset( $_POST['display_type'] ) && 'product_cat' === $taxonomy ) { // WPCS: CSRF ok, input var ok.
318 update_term_meta( $term_id, 'display_type', esc_attr( $_POST['display_type'] ) ); // WPCS: CSRF ok, sanitization ok, input var ok.
319 }
320 if ( isset( $_POST['product_cat_thumbnail_id'] ) && 'product_cat' === $taxonomy ) { // WPCS: CSRF ok, input var ok.
321 update_term_meta( $term_id, 'thumbnail_id', absint( $_POST['product_cat_thumbnail_id'] ) ); // WPCS: CSRF ok, input var ok.
322 }
323 }
324
325 /**
326 * Description for product_cat page to aid users.
327 */
328 public function product_cat_description() {
329 echo wp_kses(
330 wpautop( __( 'Product categories for your store can be managed here. To change the order of categories on the front-end you can drag and drop to sort them. To see more categories listed click the "screen options" link at the top-right of this page.', 'woocommerce' ) ),
331 array( 'p' => array() )
332 );
333 }
334
335 /**
336 * Add some notes to describe the behavior of the default category.
337 */
338 public function product_cat_notes() {
339 $category_id = get_option( 'default_product_cat', 0 );
340 $category = get_term( $category_id, 'product_cat' );
341 $category_name = ( ! $category || is_wp_error( $category ) ) ? _x( 'Uncategorized', 'Default category slug', 'woocommerce' ) : $category->name;
342 ?>
343 <div class="form-wrap edit-term-notes">
344 <p>
345 <strong><?php esc_html_e( 'Note:', 'woocommerce' ); ?></strong><br>
346 <?php
347 printf(
348 /* translators: %s: default category */
349 esc_html__( 'Deleting a category does not delete the products in that category. Instead, products that were only assigned to the deleted category are set to the category %s.', 'woocommerce' ),
350 '<strong>' . esc_html( $category_name ) . '</strong>'
351 );
352 ?>
353 </p>
354 </div>
355 <?php
356 }
357
358 /**
359 * Description for shipping class page to aid users.
360 */
361 public function product_attribute_description() {
362 echo wp_kses(
363 wpautop( __( 'Attribute terms can be assigned to products and variations.<br/><br/><b>Note</b>: Deleting a term will remove it from all products and variations to which it has been assigned. Recreating a term will not automatically assign it back to products.', 'woocommerce' ) ),
364 array( 'p' => array() )
365 );
366 }
367
368 /**
369 * Thumbnail column added to category admin.
370 *
371 * @param mixed $columns Columns array.
372 * @return array
373 */
374 public function product_cat_columns( $columns ) {
375 $new_columns = array();
376
377 if ( isset( $columns['cb'] ) ) {
378 $new_columns['cb'] = $columns['cb'];
379 unset( $columns['cb'] );
380 }
381
382 $new_columns['thumb'] = __( 'Image', 'woocommerce' );
383
384 $columns = array_merge( $new_columns, $columns );
385 $columns['handle'] = '';
386
387 return $columns;
388 }
389
390 /**
391 * Adjust row actions.
392 *
393 * @param array $actions Array of actions.
394 * @param object $term Term object.
395 * @return array
396 */
397 public function product_cat_row_actions( $actions, $term ) {
398 $default_category_id = absint( get_option( 'default_product_cat', 0 ) );
399
400 if ( $default_category_id !== $term->term_id && current_user_can( 'edit_term', $term->term_id ) ) {
401 $actions['make_default'] = sprintf(
402 '<a href="%s" aria-label="%s">%s</a>',
403 wp_nonce_url( 'edit-tags.php?action=make_default&amp;taxonomy=product_cat&amp;post_type=product&amp;tag_ID=' . absint( $term->term_id ), 'make_default_' . absint( $term->term_id ) ),
404 /* translators: %s: taxonomy term name */
405 esc_attr( sprintf( __( 'Make &#8220;%s&#8221; the default category', 'woocommerce' ), $term->name ) ),
406 __( 'Make default', 'woocommerce' )
407 );
408 }
409
410 return $actions;
411 }
412
413 /**
414 * Handle custom row actions.
415 */
416 public function handle_product_cat_row_actions() {
417 if ( isset( $_GET['action'], $_GET['tag_ID'], $_GET['_wpnonce'] ) && 'make_default' === $_GET['action'] ) { // WPCS: CSRF ok, input var ok.
418 $make_default_id = absint( $_GET['tag_ID'] ); // WPCS: Input var ok.
419
420 if ( wp_verify_nonce( $_GET['_wpnonce'], 'make_default_' . $make_default_id ) && current_user_can( 'edit_term', $make_default_id ) ) { // WPCS: Sanitization ok, input var ok, CSRF ok.
421 update_option( 'default_product_cat', $make_default_id );
422 }
423 }
424 }
425
426 /**
427 * Thumbnail column value added to category admin.
428 *
429 * @param string $columns Column HTML output.
430 * @param string $column Column name.
431 * @param int $id Product ID.
432 *
433 * @return string
434 */
435 public function product_cat_column( $columns, $column, $id ) {
436 if ( 'thumb' === $column ) {
437 // Prepend tooltip for default category.
438 $default_category_id = absint( get_option( 'default_product_cat', 0 ) );
439
440 if ( $default_category_id === $id ) {
441 $columns .= wc_help_tip( __( 'This is the default category and it cannot be deleted. It will be automatically assigned to products with no category.', 'woocommerce' ) );
442 }
443
444 $thumbnail_id = get_term_meta( $id, 'thumbnail_id', true );
445
446 if ( $thumbnail_id ) {
447 $image = wp_get_attachment_thumb_url( $thumbnail_id );
448 } else {
449 $image = wc_placeholder_img_src();
450 }
451
452 // Prevent esc_url from breaking spaces in urls for image embeds. Ref: https://core.trac.wordpress.org/ticket/23605 .
453 $image = str_replace( ' ', '%20', $image );
454 $columns .= '<img src="' . esc_url( $image ) . '" alt="' . esc_attr__( 'Thumbnail', 'woocommerce' ) . '" class="wp-post-image" height="48" width="48" />';
455 }
456 if ( 'handle' === $column ) {
457 $columns .= '<input type="hidden" name="term_id" value="' . esc_attr( $id ) . '" />';
458 }
459 return $columns;
460 }
461
462 /**
463 * Maintain term hierarchy when editing a product.
464 *
465 * @param array $args Term checklist args.
466 * @return array
467 */
468 public function disable_checked_ontop( $args ) {
469 if ( ! empty( $args['taxonomy'] ) && 'product_cat' === $args['taxonomy'] ) {
470 $args['checked_ontop'] = false;
471 }
472 return $args;
473 }
474
475 /**
476 * Admin footer scripts for the product categories admin screen
477 *
478 * @return void
479 */
480 public function scripts_at_product_cat_screen_footer() {
481 $taxonomy = isset( $_GET['taxonomy'] ) ? sanitize_text_field( wp_unslash( $_GET['taxonomy'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
482 if ( 'product_cat' !== $taxonomy ) {
483 return;
484 }
485
486 $handle = 'wc-admin-taxonomies';
487 wp_register_script( $handle, '', array(), WC_VERSION, array( 'in_footer' => true ) );
488 wp_enqueue_script( $handle );
489
490 // Ensure the tooltip is displayed when the image column is disabled on product categories.
491 wp_add_inline_script(
492 $handle,
493 sprintf(
494 "(function() {
495 'use strict';
496 const product_cat = document.getElementById('tag-%d');
497 if (product_cat) {
498 const th = product_cat.querySelector('th');
499 const thumbSpan = product_cat.querySelector('td.thumb span');
500 if (th && thumbSpan) {
501 th.innerHTML = '';
502 th.appendChild(thumbSpan);
503 }
504 }
505 })();",
506 absint( $this->default_cat_id )
507 )
508 );
509 }
510 }
511
512 $wc_admin_taxonomies = WC_Admin_Taxonomies::get_instance();
513