PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 11.1.0-beta.2
WooCommerce v11.1.0-beta.2
11.1.0 11.1.0-rc.2 11.1.0-rc.1 11.1.0-beta.2 11.1.0-beta.1 11.0.1 11.0.0 11.0.0-rc.3 11.0.0-rc.2 11.0.0-rc.1 11.0.0-beta.2 11.0.0-beta.1 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 / src / Internal / ProductAttributes / VisualAttributeTermAdmin.php
woocommerce / src / Internal / ProductAttributes Last commit date
AttributeSlugLength.php 2 weeks ago VisualAttributeTermAdmin.php 2 weeks ago VisualAttributeTermMeta.php 2 months ago
VisualAttributeTermAdmin.php
560 lines
1 <?php
2 /**
3 * Visual attribute term admin fields.
4 *
5 * @package WooCommerce\Classes
6 */
7
8 declare( strict_types = 1 );
9
10 namespace Automattic\WooCommerce\Internal\ProductAttributes;
11
12 use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
13 use Automattic\WooCommerce\Internal\RegisterHooksInterface;
14
15 /**
16 * Admin UI for wc-visual attribute term metadata.
17 *
18 * @internal
19 *
20 * @since 10.9.0
21 */
22 class VisualAttributeTermAdmin implements RegisterHooksInterface {
23
24 /**
25 * Register hooks.
26 *
27 * @return void
28 */
29 public function register(): void {
30 if ( ! is_admin() ) {
31 return;
32 }
33
34 add_action( 'created_term', array( $this, 'save_product_attribute_term_fields' ), 10, 3 );
35 add_action( 'edit_term', array( $this, 'save_product_attribute_term_fields' ), 10, 3 );
36
37 foreach ( wc_get_attribute_taxonomies() as $attribute ) {
38 $taxonomy = 'pa_' . $attribute->attribute_name;
39
40 add_action( $taxonomy . '_add_form_fields', array( $this, 'add_product_attribute_term_fields' ) );
41 add_action( $taxonomy . '_edit_form_fields', array( $this, 'edit_product_attribute_term_fields' ), 10, 1 );
42 add_filter(
43 "manage_edit-{$taxonomy}_columns",
44 function ( $columns ) use ( $taxonomy ) {
45 return $this->add_term_visual_column( $columns, $taxonomy );
46 }
47 );
48 add_filter(
49 "manage_{$taxonomy}_custom_column",
50 function ( $content, $column, $term_id ) use ( $taxonomy ) {
51 return $this->render_term_visual_column( $content, $column, $term_id, $taxonomy );
52 },
53 10,
54 3
55 );
56 }
57
58 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_visual_attribute_script' ) );
59 add_filter( 'woocommerce_json_search_found_product_attribute_terms', array( $this, 'add_visual_data_to_attribute_terms' ), 10, 2 );
60 }
61
62 /**
63 * Add visual swatch data to attribute term search results.
64 *
65 * @internal
66 *
67 * @param array|\WP_Error $terms The list of matched terms.
68 * @param string $taxonomy The terms taxonomy.
69 * @return array|\WP_Error
70 */
71 public function add_visual_data_to_attribute_terms( $terms, string $taxonomy ) {
72 if ( is_wp_error( $terms ) || empty( $terms ) || ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
73 return $terms;
74 }
75
76 // Because `$terms` might be filtered by a plugin, make sure we only operate on valid terms.
77 $valid_terms = array_filter(
78 $terms,
79 static function ( $term ) {
80 return is_object( $term ) && isset( $term->term_id );
81 }
82 );
83
84 $term_ids = array_map( 'intval', wp_list_pluck( $valid_terms, 'term_id' ) );
85 $visuals = VisualAttributeTermMeta::get_term_visuals( $term_ids );
86
87 foreach ( $valid_terms as $term ) {
88 /**
89 * Term object with dynamic visual property.
90 *
91 * @var \stdClass $term
92 */
93 $term->visual = $visuals[ $term->term_id ] ?? VisualAttributeTermMeta::get_empty_visual();
94 }
95
96 return $terms;
97 }
98
99 /**
100 * Add custom fields for product attribute terms.
101 *
102 * @internal
103 *
104 * @param string $taxonomy Taxonomy slug.
105 * @return void
106 */
107 public function add_product_attribute_term_fields( $taxonomy ): void {
108 if ( ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
109 return;
110 }
111
112 self::render_div_visual_attribute_fields( 'term-' );
113 }
114
115 /**
116 * Edit custom fields for product attribute terms.
117 *
118 * @internal
119 *
120 * @param \WP_Term $term Current term.
121 * @return void
122 */
123 public function edit_product_attribute_term_fields( $term ): void {
124 if ( ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $term->taxonomy ) ) {
125 return;
126 }
127
128 self::render_table_visual_attribute_fields( $term );
129 }
130
131 /**
132 * Render visual fields for the add attribute term modal.
133 *
134 * @internal
135 *
136 * @return void
137 */
138 public static function render_add_attribute_term_modal_fields(): void {
139 self::render_div_visual_attribute_fields( 'wc-modal-add-attribute-term-' );
140 }
141
142 /**
143 * Render visual attribute fields for add forms.
144 *
145 * @param string $field_id_prefix Field ID prefix.
146 * @return void
147 */
148 private static function render_div_visual_attribute_fields( string $field_id_prefix ): void {
149 ?>
150 <div class="form-field wc-admin-visual-attribute-type">
151 <label><?php esc_html_e( 'Swatch type', 'woocommerce' ); ?></label>
152 <?php self::render_visual_type_inputs( $field_id_prefix, VisualAttributeTermMeta::TYPE_COLOR ); ?>
153 </div>
154 <div class="form-field wc-admin-visual-attribute-color">
155 <?php self::render_color_input( $field_id_prefix, '' ); ?>
156 </div>
157 <div class="form-field wc-admin-visual-attribute-image">
158 <?php self::render_image_input( $field_id_prefix, 0 ); ?>
159 </div>
160 <?php
161 }
162
163 /**
164 * Render visual attribute fields for edit forms.
165 *
166 * @param \WP_Term $term Current term.
167 * @return void
168 */
169 private static function render_table_visual_attribute_fields( \WP_Term $term ): void {
170 $color_value = get_term_meta( $term->term_id, 'color', true );
171 $color_value = is_string( $color_value ) ? $color_value : '';
172 $image_value = absint( get_term_meta( $term->term_id, 'image', true ) );
173 $visual_type = $image_value > 0 ? VisualAttributeTermMeta::TYPE_IMAGE : VisualAttributeTermMeta::TYPE_COLOR;
174 $field_prefix = 'term-';
175 ?>
176 <tr class="form-field wc-admin-visual-attribute-type">
177 <th scope="row" valign="top">
178 <label><?php esc_html_e( 'Swatch type', 'woocommerce' ); ?></label>
179 </th>
180 <td><?php self::render_visual_type_inputs( $field_prefix, $visual_type ); ?></td>
181 </tr>
182 <tr class="form-field wc-admin-visual-attribute-color">
183 <th scope="row" valign="top">
184 <label for="<?php echo esc_attr( self::get_color_input_id( $field_prefix ) ); ?>"><?php esc_html_e( 'Color value', 'woocommerce' ); ?></label>
185 </th>
186 <td><?php self::render_color_input_control( $field_prefix, $color_value ); ?></td>
187 </tr>
188 <tr class="form-field wc-admin-visual-attribute-image">
189 <th scope="row" valign="top">
190 <label for="<?php echo esc_attr( self::get_image_input_id( $field_prefix ) ); ?>"><?php esc_html_e( 'Image value', 'woocommerce' ); ?></label>
191 </th>
192 <td><?php self::render_image_input_control( $field_prefix, $image_value ); ?></td>
193 </tr>
194 <?php
195 }
196
197 /**
198 * Render visual type radio inputs.
199 *
200 * @param string $field_id_prefix Field ID prefix.
201 * @param string $selected_type Selected visual type.
202 * @return void
203 */
204 private static function render_visual_type_inputs( string $field_id_prefix, string $selected_type ): void {
205 $color_id = $field_id_prefix . 'visual-type-color';
206 $image_id = $field_id_prefix . 'visual-type-image';
207 ?>
208 <fieldset>
209 <label for="<?php echo esc_attr( $color_id ); ?>">
210 <input
211 type="radio"
212 id="<?php echo esc_attr( $color_id ); ?>"
213 name="wc_visual_attribute_type"
214 value="<?php echo esc_attr( VisualAttributeTermMeta::TYPE_COLOR ); ?>"
215 <?php checked( VisualAttributeTermMeta::TYPE_COLOR, $selected_type ); ?>
216 />
217 <?php esc_html_e( 'Color', 'woocommerce' ); ?>
218 </label>
219 <label for="<?php echo esc_attr( $image_id ); ?>">
220 <input
221 type="radio"
222 id="<?php echo esc_attr( $image_id ); ?>"
223 name="wc_visual_attribute_type"
224 value="<?php echo esc_attr( VisualAttributeTermMeta::TYPE_IMAGE ); ?>"
225 <?php checked( VisualAttributeTermMeta::TYPE_IMAGE, $selected_type ); ?>
226 />
227 <?php esc_html_e( 'Image', 'woocommerce' ); ?>
228 </label>
229 </fieldset>
230 <?php
231 }
232
233 /**
234 * Render the color input and label.
235 *
236 * @param string $field_id_prefix Field ID prefix.
237 * @param string $color_value Color value.
238 * @return void
239 */
240 private static function render_color_input( string $field_id_prefix, string $color_value ): void {
241 ?>
242 <label for="<?php echo esc_attr( self::get_color_input_id( $field_id_prefix ) ); ?>"><?php esc_html_e( 'Color value', 'woocommerce' ); ?></label>
243 <?php self::render_color_input_control( $field_id_prefix, $color_value ); ?>
244 <?php
245 }
246
247 /**
248 * Render the color input control.
249 *
250 * @param string $field_id_prefix Field ID prefix.
251 * @param string $color_value Color value.
252 * @return void
253 */
254 private static function render_color_input_control( string $field_id_prefix, string $color_value ): void {
255 ?>
256 <input name="term_color" id="<?php echo esc_attr( self::get_color_input_id( $field_id_prefix ) ); ?>" class="wc-admin-visual-attribute-color-input" type="text" value="<?php echo esc_attr( $color_value ); ?>" />
257 <?php
258 }
259
260 /**
261 * Render the image input and label.
262 *
263 * @param string $field_id_prefix Field ID prefix.
264 * @param int $image_value Image attachment ID.
265 * @return void
266 */
267 private static function render_image_input( string $field_id_prefix, int $image_value ): void {
268 ?>
269 <label for="<?php echo esc_attr( self::get_image_input_id( $field_id_prefix ) ); ?>"><?php esc_html_e( 'Image value', 'woocommerce' ); ?></label>
270 <?php self::render_image_input_control( $field_id_prefix, $image_value ); ?>
271 <?php
272 }
273
274 /**
275 * Render the image input control.
276 *
277 * @param string $field_id_prefix Field ID prefix.
278 * @param int $image_value Image attachment ID.
279 * @return void
280 */
281 private static function render_image_input_control( string $field_id_prefix, int $image_value ): void {
282 ?>
283 <input name="term_image" id="<?php echo esc_attr( self::get_image_input_id( $field_id_prefix ) ); ?>" class="wc-admin-visual-attribute-image-input" type="hidden" value="<?php echo absint( $image_value ); ?>" />
284 <?php
285 }
286
287 /**
288 * Get color input ID.
289 *
290 * @param string $field_id_prefix Field ID prefix.
291 * @return string
292 */
293 private static function get_color_input_id( string $field_id_prefix ): string {
294 return $field_id_prefix . 'color';
295 }
296
297 /**
298 * Get image input ID.
299 *
300 * @param string $field_id_prefix Field ID prefix.
301 * @return string
302 */
303 private static function get_image_input_id( string $field_id_prefix ): string {
304 return $field_id_prefix . 'image';
305 }
306
307 /**
308 * Enqueue the visual attribute script.
309 *
310 * @internal
311 *
312 * @return void
313 */
314 public function enqueue_visual_attribute_script(): void {
315 $screen = get_current_screen();
316
317 if ( ! $screen || ! is_string( $screen->id ) ) {
318 return;
319 }
320
321 $is_product_editor_screen = 'product' === $screen->id;
322
323 if ( $is_product_editor_screen && array_key_exists( 'wc-visual', wc_get_attribute_types() ) ) {
324 wp_enqueue_media();
325 WCAdminAssets::register_script( 'wp-admin-scripts', 'visual-attribute-picker', true, array( 'wp-components' ) );
326 return;
327 }
328
329 $is_attribute_term_screen = 0 === strpos( $screen->id, 'edit-pa_' );
330 $taxonomy = $this->get_current_taxonomy();
331
332 if ( $is_attribute_term_screen && VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
333 wp_enqueue_media();
334 WCAdminAssets::register_script( 'wp-admin-scripts', 'visual-attribute-picker', true, array( 'wp-components' ) );
335 }
336 }
337
338 /**
339 * Save product attribute term fields.
340 *
341 * @internal
342 *
343 * @param mixed $term_id Term ID being saved.
344 * @param mixed $tt_id Term taxonomy ID.
345 * @param string $taxonomy Taxonomy slug.
346 * @return void
347 */
348 public function save_product_attribute_term_fields( $term_id, $tt_id = '', $taxonomy = '' ): void {
349 if ( $this->is_ajax_add_attribute_request() ) {
350 return;
351 }
352
353 VisualAttributeTermMeta::save_term_visual_from_request( (int) $term_id, $taxonomy, $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
354 }
355
356 /**
357 * Add visual column for product attribute terms.
358 *
359 * @internal
360 *
361 * @param array $columns Existing columns.
362 * @param string $taxonomy Taxonomy slug.
363 * @return array
364 */
365 public function add_term_visual_column( $columns, $taxonomy ): array {
366 if ( ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
367 return $columns;
368 }
369
370 $new_columns = array();
371 foreach ( $columns as $key => $label ) {
372 if ( 'slug' === $key ) {
373 $new_columns['visual'] = __( 'Visual', 'woocommerce' );
374 }
375 $new_columns[ $key ] = $label;
376 }
377
378 if ( ! isset( $new_columns['visual'] ) ) {
379 $new_columns['visual'] = __( 'Visual', 'woocommerce' );
380 }
381
382 return $new_columns;
383 }
384
385 /**
386 * Render visual column for product attribute terms.
387 *
388 * @internal
389 *
390 * @param string $content Column output so far.
391 * @param string $column Current column key.
392 * @param int $term_id Term ID.
393 * @param string $taxonomy Taxonomy slug.
394 * @return string
395 */
396 public function render_term_visual_column( $content, $column, $term_id, $taxonomy ): string {
397 if ( 'visual' !== $column || ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
398 return $content;
399 }
400
401 $image_id = absint( get_term_meta( $term_id, 'image', true ) );
402
403 if ( $image_id && wp_attachment_is_image( $image_id ) ) {
404 $thumbnail = wp_get_attachment_image( $image_id, array( 32, 32 ) );
405
406 return $thumbnail ? $thumbnail : '&ndash;';
407 }
408
409 $color_value = sanitize_hex_color( get_term_meta( $term_id, 'color', true ) );
410
411 if ( ! $color_value ) {
412 return '&ndash;';
413 }
414
415 $swatch = sprintf(
416 '<span class="wc-admin-color-swatch" style="background-color:%s;" aria-hidden="true"></span>',
417 esc_attr( $color_value )
418 );
419
420 return $swatch . esc_html( strtoupper( $color_value ) );
421 }
422
423 /**
424 * Check whether the current request is the add attribute AJAX action.
425 *
426 * @return bool
427 */
428 private function is_ajax_add_attribute_request(): bool {
429 $action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
430
431 return wp_doing_ajax() && 'woocommerce_add_new_attribute' === $action;
432 }
433
434 /**
435 * Get current taxonomy from request.
436 *
437 * @return string
438 */
439 private function get_current_taxonomy(): string {
440 return isset( $_GET['taxonomy'] ) ? sanitize_text_field( wp_unslash( $_GET['taxonomy'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
441 }
442
443 /**
444 * Get the default color terms to create for a new wc-visual attribute.
445 *
446 * @return array<string, array{label: string, color: string}>
447 */
448 private static function get_default_color_terms(): array {
449 return array(
450 'black' => array(
451 'label' => __( 'Black', 'woocommerce' ),
452 'color' => '#121212',
453 ),
454 'white' => array(
455 'label' => __( 'White', 'woocommerce' ),
456 'color' => '#FFFFFF',
457 ),
458 'gray' => array(
459 'label' => __( 'Gray', 'woocommerce' ),
460 'color' => '#6E6E6E',
461 ),
462 'red' => array(
463 'label' => __( 'Red', 'woocommerce' ),
464 'color' => '#D32F2F',
465 ),
466 'blue' => array(
467 'label' => __( 'Blue', 'woocommerce' ),
468 'color' => '#1976D2',
469 ),
470 'green' => array(
471 'label' => __( 'Green', 'woocommerce' ),
472 'color' => '#388E3C',
473 ),
474 'yellow' => array(
475 'label' => __( 'Yellow', 'woocommerce' ),
476 'color' => '#FBE02D',
477 ),
478 'pink' => array(
479 'label' => __( 'Pink', 'woocommerce' ),
480 'color' => '#EC407A',
481 ),
482 'brown' => array(
483 'label' => __( 'Brown', 'woocommerce' ),
484 'color' => '#5D4037',
485 ),
486 );
487 }
488
489 /**
490 * Seed default color terms for a newly created wc-visual attribute.
491 *
492 * @internal
493 *
494 * @param int $attribute_id Attribute ID.
495 * @return void
496 */
497 public static function seed_visual_attribute_terms( int $attribute_id ): void {
498 if ( 0 >= $attribute_id ) {
499 return;
500 }
501
502 $attribute = wc_get_attribute( $attribute_id );
503
504 if (
505 ! $attribute ||
506 ! isset( $attribute->slug, $attribute->type ) ||
507 'wc-visual' !== $attribute->type
508 ) {
509 return;
510 }
511
512 $taxonomy = $attribute->slug;
513
514 // Taxonomy is registered on init from the cached list but not yet available
515 // at process_add_attribute time (cache invalidated after wc_create_attribute).
516 // Use the same WC filter seams as WC_Post_Types::register_taxonomies().
517 if ( ! taxonomy_exists( $taxonomy ) ) {
518 /**
519 * Filters the object types for a WooCommerce taxonomy.
520 *
521 * @param array $objects Object types.
522 *
523 * @since 11.0.0
524 */
525 $objects = apply_filters( "woocommerce_taxonomy_objects_{$taxonomy}", array( 'product' ) );
526 /**
527 * Filters the arguments for a WooCommerce taxonomy.
528 *
529 * @param array $args Taxonomy arguments.
530 *
531 * @since 11.0.0
532 */
533 $args = apply_filters(
534 "woocommerce_taxonomy_args_{$taxonomy}",
535 array(
536 'hierarchical' => false,
537 'public' => false,
538 'show_ui' => false,
539 'show_in_menu' => false,
540 )
541 );
542 register_taxonomy( $taxonomy, $objects, $args );
543 }
544
545 foreach ( self::get_default_color_terms() as $slug => $term ) {
546 if ( get_term_by( 'slug', $slug, $taxonomy ) ) {
547 continue;
548 }
549
550 $result = wp_insert_term( $term['label'], $taxonomy, array( 'slug' => $slug ) );
551
552 if ( is_wp_error( $result ) || empty( $result['term_id'] ) ) {
553 continue;
554 }
555
556 VisualAttributeTermMeta::save_term_visual( (int) $result['term_id'], $term['color'], 0 );
557 }
558 }
559 }
560