Skip to content

Commit

Permalink
Update empty state for product attributes tab (#38126)
Browse files Browse the repository at this point in the history
* Remove empty state HTML

* Add empty attribute when product has no attributes

* Remove unused woocommerce_admin_meta_boxes.has_local_attributes

* Remove unused toggle_add_global_attribute_layout

* Remove unused button.add_attribute click handling (button doesn't exist anymore)

* Fix positioning of Expand / Close

* Remove unnecessary add-attribute-container div

* Refactor attribute search selection handling

* Remove empty attribute if adding an existing attribute

* Update e2e test clicking of "Add new" attribute button

* Update Tracks handling for "Add new" attribute button

* Changelog

* Fix action recorded when "Add new" button is clicked

* Remove console.log statements

* Allow propagation of click event on "Create value" button

* Move Tracks wcadmin_product_attributes_buttons action: 'add_existing' to product-tracking TS

* Make function names more descriptive. Add comment to clarify why event.preventDefault is used.
  • Loading branch information
mattsherman committed May 10, 2023
1 parent 2276953 commit d11f50b
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 184 deletions.
Expand Up @@ -412,59 +412,53 @@ const attachProductTagsTracks = () => {
* Attaches attributes tracks.
*/
const attachAttributesTracks = () => {
function addNewTermEventHandler() {
recordEvent( 'product_attributes_add_term', {
page: 'product',
} );
}

function addNewAttributeTermTracks() {
const addNewTermButtons = document.querySelectorAll(
'.woocommerce_attribute .add_new_attribute'
);
addNewTermButtons.forEach( ( button ) => {
button.removeEventListener( 'click', addNewTermEventHandler );
button.addEventListener( 'click', addNewTermEventHandler );
} );
}
addNewAttributeTermTracks();

document
.querySelector( '.add_attribute' )
?.addEventListener( 'click', () => {
setTimeout( () => {
addNewAttributeTermTracks();
}, 1000 );
} );
attachEventListenerToParentForChildren( '#product_attributes', [
{
eventName: 'click',
childQuery: '.add_new_attribute',
callback: () => {
recordEvent( 'product_attributes_add_term', {
page: 'product',
} );
},
},
] );
};

/**
* Attaches product attributes tracks.
* Attaches Tracks event for when a new custom attribute is added to a product.
*/
const attachProductAttributesTracks = () => {
const attachAddCustomAttributeTracks = () => {
document
.querySelector( '#product_attributes .add_custom_attribute' )
?.addEventListener( 'click', () => {
recordEvent( 'product_attributes_buttons', {
action: 'add_first_attribute',
action: 'add_new',
} );
} );
document
.querySelector( '#product_attributes .add_attribute' )
?.addEventListener( 'click', () => {
// We verify that we are not adding an existing attribute to not
// duplicate the recorded event.
const selectElement = document.querySelector(
'.attribute_taxonomy'
) as HTMLSelectElement;
// Get the index of the selected option
const selectedIndex = selectElement.selectedIndex;
if ( selectElement.options[ selectedIndex ]?.value === '' ) {
recordEvent( 'product_attributes_buttons', {
action: 'add_new',
} );
}
};

/**
* Attaches Tracks event for when an existing global attribute is added to a product.
*/
const attachAddExistingAttributeTracks = () => {
window
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Need to use jQuery to hook up to the select2:select event since the select2 component is jQuery-based
?.jQuery( 'select.wc-attribute-search' )
.on( 'select2:select', function () {
recordEvent( 'product_attributes_buttons', {
action: 'add_existing',
} );
} );
};

/**
* Attaches product attributes tracks.
*/
const attachProductAttributesTracks = () => {
attachAddCustomAttributeTracks();
attachAddExistingAttributeTracks();

const attributesSection = '#product_attributes';

Expand Down
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/update-attribute-empty-state
@@ -0,0 +1,4 @@
Significance: minor
Type: update

Update empty state for product attributes tab.
115 changes: 45 additions & 70 deletions plugins/woocommerce/client/legacy/js/admin/meta-boxes-product.js
Expand Up @@ -57,12 +57,6 @@ jQuery( function ( $ ) {
} );
} );

$( function () {
if ( ! woocommerce_admin_meta_boxes.has_local_attributes ) {
$( 'button.add_attribute' ).trigger( 'click' );
}
} );

// Catalog Visibility.
$( '#catalog-visibility' )
.find( '.edit-catalog-visibility' )
Expand Down Expand Up @@ -400,6 +394,14 @@ jQuery( function ( $ ) {
.find( '.woocommerce_attribute' )
.get();

// If the product has no attributes, add an empty attribute to be filled out by the user.
$( function add_blank_custom_attribute_if_no_attributes() {

if ( woocommerce_attribute_items.length === 0 ) {
$( 'button.add_custom_attribute' ).trigger( 'click' );
}
} );

woocommerce_attribute_items.sort( function ( a, b ) {
var compA = parseInt( $( a ).attr( 'rel' ), 10 );
var compB = parseInt( $( b ).attr( 'rel' ), 10 );
Expand Down Expand Up @@ -445,12 +447,6 @@ jQuery( function ( $ ) {
selectedAttributes
);

function toggle_add_global_attribute_layout() {
$( 'div.add-attribute-container' ).toggle();
$( 'div.add-global-attribute-container' ).toggle();
$( '#product_attributes > .toolbar-buttons' ).toggle();
}

function add_attribute( element, attribute ) {
var size = $( '.product_attributes .woocommerce_attribute' ).length;
var $wrapper = $( element ).closest( '#product_attributes' );
Expand Down Expand Up @@ -504,64 +500,52 @@ jQuery( function ( $ ) {
}
}

$( 'select.wc-attribute-search' ).on( 'select2:select', function ( e ) {
if ( e.params && e.params.data && e.params.data.id ) {
add_attribute( this, e.params.data.id );
if ( ! selectedAttributes.includes( e.params.data.id ) ) {
selectedAttributes.push( e.params.data.id );
$( 'select.wc-attribute-search' ).data(
'disabled-items',
selectedAttributes
);
function add_if_not_exists( arr, item ) {
return arr.includes( item ) ? attr : [ ...arr, item ];
}

function disable_in_attribute_search( selectedAttributes ) {
$( 'select.wc-attribute-search' ).data( 'disabled-items', selectedAttributes );
}

function remove_blank_custom_attribute_if_no_other_attributes() {
const $attributes = $( '.product_attributes .woocommerce_attribute' );

if ( $attributes.length === 1 ) {
const $attribute = $attributes.first();

const $attributeName = $attribute.find( 'input[name="attribute_names[0]"]' );
const $attributeValue = $attribute.find( 'input[name="attribute_values[0]"]' );

if ( ! $attributeName.val() && ! $attributeValue.val() ) {
$attribute.remove();
}
window.wcTracks.recordEvent( 'product_attributes_buttons', {
action: 'add_existing',
} );
}
}

$( 'select.wc-attribute-search' ).on( 'select2:select', function ( e ) {
const attributeId = e?.params?.data?.id;

if ( attributeId ) {
remove_blank_custom_attribute_if_no_other_attributes();

add_attribute( this, attributeId );

selectedAttributes = add_if_not_exists( selectedAttributes, attributeId );
disable_in_attribute_search( selectedAttributes );
}

$( this ).val( null );
$( this ).trigger( 'change' );
if (
$( 'div.add-attribute-container' ).hasClass( 'hidden' ) &&
! $( 'div.add-global-attribute-container' ).hasClass( 'hidden' )
) {
toggle_add_global_attribute_layout();
}

return false;
} );

// Add rows.
$( 'button.add_attribute' ).on( 'click', function () {
var attribute = $( 'select.attribute_taxonomy' ).val();
if (
! attribute &&
$( 'select.attribute_taxonomy' ).hasClass( 'wc-attribute-search' )
) {
return;
}
add_attribute( this, attribute );
$( 'select.attribute_taxonomy' ).val( null );
$( 'select.attribute_taxonomy' ).trigger( 'change' );

// We record the event only when an existing attribute is added.
if ( attribute !== '' ) {
window.wcTracks.recordEvent( 'product_attributes_buttons', {
action: 'add_existing',
} );
}

return false;
} );

$( 'button.add_custom_attribute' ).on( 'click', function () {
add_attribute( this, '' );

if (
$( 'div.add-attribute-container' ).hasClass( 'hidden' ) &&
! $( 'div.add-global-attribute-container' ).hasClass( 'hidden' )
) {
toggle_add_global_attribute_layout();
}
return false;
} );

Expand Down Expand Up @@ -694,16 +678,6 @@ jQuery( function ( $ ) {
action: 'remove_attribute',
} );

if (
! $( '.woocommerce_attribute_data' ).is( ':visible' ) &&
! $( 'div.add-global-attribute-container' ).hasClass(
'hidden'
) &&
$( '.product_attributes' ).find( 'input, select, textarea' )
.length === 0
) {
toggle_add_global_attribute_layout();
}
jQuery.maybe_disable_save_button();
}
return false;
Expand Down Expand Up @@ -734,7 +708,10 @@ jQuery( function ( $ ) {
$( '.product_attributes' ).on(
'click',
'button.add_new_attribute',
function () {
function ( event ) {
// prevent form submission but allow event propagation
event.preventDefault();

$( '.product_attributes' ).block( {
message: null,
overlayCSS: {
Expand Down Expand Up @@ -784,8 +761,6 @@ jQuery( function ( $ ) {
} else {
$( '.product_attributes' ).unblock();
}

return false;
}
);

Expand Down
Expand Up @@ -416,7 +416,6 @@ public function admin_scripts() {
'rounding_precision' => wc_get_rounding_precision(),
'tax_rounding_mode' => wc_get_tax_rounding_mode(),
'product_types' => array_unique( array_merge( array( 'simple', 'grouped', 'variable', 'external' ), array_keys( wc_get_product_types() ) ) ),
'has_local_attributes' => ! empty( wc_get_attribute_taxonomies() ),
'i18n_download_permission_fail' => __( 'Could not grant access - the user may already have permission for this file or billing email is not set. Ensure the billing email is set, and the order has been saved.', 'woocommerce' ),
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),
Expand Down
Expand Up @@ -13,78 +13,27 @@
// Array of defined attribute taxonomies.
$attribute_taxonomies = wc_get_attribute_taxonomies();
// Product attributes - taxonomies and custom, ordered, with visibility and variation attributes set.
$product_attributes = $product_object->get_attributes( 'edit' );
$has_local_attributes = empty( $attribute_taxonomies );
$has_global_attributes = empty( $product_attributes );
$is_add_global_attribute_visible = ! $has_local_attributes && $has_global_attributes;
$icon_url = WC_ADMIN_IMAGES_FOLDER_URL . '/icons/global-attributes-icon.svg';
$product_attributes = $product_object->get_attributes( 'edit' );
?>
<div id="product_attributes" class="panel wc-metaboxes-wrapper hidden">
<div class="toolbar toolbar-top <?php echo $is_add_global_attribute_visible ? ' expand-close-hidden' : ''; ?>">
<div class="add-global-attribute-container<?php echo $is_add_global_attribute_visible ? '' : ' hidden'; ?>">
<div class="actions">
<button type="button" class="button add_custom_attribute"><?php esc_html_e( 'Add new', 'woocommerce' ); ?></button>
<select class="wc-attribute-search" data-placeholder="<?php esc_attr_e( 'Add existing', 'woocommerce' ); ?>" data-minimum-input-length="0">
</select>
</div>
<div class="message">
<img src="<?php echo esc_url( $icon_url ); ?>" />
<p>
<?php
esc_html_e(
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
'woocommerce'
);
?>
</p>
</div>
</div>
<div class="add-attribute-container<?php echo $is_add_global_attribute_visible ? ' hidden' : ' '; ?>">
<?php
if ( $has_local_attributes && $has_global_attributes ) :
?>
<div id="message" class="inline notice woocommerce-message">
<p>
<?php
esc_html_e(
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
'woocommerce'
);
?>
</p>
</div>
<?php endif; ?>
<span class="expand-close">
<a href="#" class="expand_all"><?php esc_html_e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php esc_html_e( 'Close', 'woocommerce' ); ?></a>
</span>

<?php
/**
* Filter for the attribute taxonomy filter dropdown threshold.
*
* @since 7.0.0
* @param number $threshold The threshold for showing the simple dropdown.
*/
if ( count( $attribute_taxonomies ) <= apply_filters( 'woocommerce_attribute_taxonomy_filter_threshold', 20 ) ) :
?>
<select name="attribute_taxonomy" class="attribute_taxonomy">
<option value=""><?php esc_html_e( 'Custom product attribute', 'woocommerce' ); ?></option>
<div class="toolbar toolbar-top">
<div id="message" class="inline notice woocommerce-message">
<p>
<?php
if ( ! $has_local_attributes ) {
foreach ( $attribute_taxonomies as $attr_taxonomy ) {
$attribute_taxonomy_name = wc_attribute_taxonomy_name( $attr_taxonomy->attribute_name );
$label = $attr_taxonomy->attribute_label ? $attr_taxonomy->attribute_label : $attr_taxonomy->attribute_name;
echo '<option value="' . esc_attr( $attribute_taxonomy_name ) . '">' . esc_html( $label ) . '</option>';
}
}
esc_html_e(
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
'woocommerce'
);
?>
</p>
</div>
<span class="expand-close">
<a href="#" class="expand_all"><?php esc_html_e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php esc_html_e( 'Close', 'woocommerce' ); ?></a>
</span>
<div class="actions">
<button type="button" class="button add_custom_attribute"><?php esc_html_e( 'Add new', 'woocommerce' ); ?></button>
<select class="wc-attribute-search" data-placeholder="<?php esc_attr_e( 'Add existing', 'woocommerce' ); ?>" data-minimum-input-length="0">
</select>
<button type="button" class="button add_attribute"><?php esc_html_e( 'Add', 'woocommerce' ); ?></button>
<?php else : ?>
<button type="button" class="button add_custom_attribute"><?php esc_html_e( 'Add custom attribute', 'woocommerce' ); ?></button>
<select class="wc-attribute-search attribute_taxonomy" id="attribute_taxonomy" name="attribute_taxonomy" data-placeholder="<?php esc_attr_e( 'Add existing attribute', 'woocommerce' ); ?>" data-minimum-input-length="0">
</select>
<?php endif; ?>
</div>
</div>
<div class="product_attributes wc-metaboxes">
Expand All @@ -104,7 +53,7 @@
}
?>
</div>
<div class="toolbar toolbar-buttons<?php echo $is_add_global_attribute_visible ? ' hidden' : ''; ?>">
<div class="toolbar toolbar-buttons">
<span class="expand-close">
<a href="#" class="expand_all"><?php esc_html_e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php esc_html_e( 'Close', 'woocommerce' ); ?></a>
</span>
Expand Down

0 comments on commit d11f50b

Please sign in to comment.