Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update empty state for product attributes tab #38126

Merged
merged 17 commits into from May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function doesn't necessarily need to be named, especially if it's only being used in this one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming functions is very helpful when you are looking at an outline of the code in an editor, debugging a stack trace, and to help document what the code is doing.


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();
mattsherman marked this conversation as resolved.
Show resolved Hide resolved

$( '.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