register_admin_hooks();
}
$this->register_global_hooks();
}
/**
* Register the admin-side hooks
*
* @since 1.3.8.2
*/
public function register_admin_hooks() {
// Add extra links to the plugin desc row.
add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
// Enqueue scripts.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
// Show the right stock status on WC products list when ATUM is managing the stock.
add_filter( 'woocommerce_admin_stock_html', array( $this, 'set_wc_products_list_stock_status' ), 10, 2 );
// Add the location column to the items table in WC orders.
add_action( 'woocommerce_admin_order_item_headers', array( $this, 'wc_order_add_location_column_header' ) );
add_action( 'woocommerce_admin_order_item_values', array( $this, 'wc_order_add_location_column_value' ), 10, 3 );
// Firefox fix to not preserve the dropdown.
add_filter( 'wp_dropdown_cats', array( $this, 'set_dropdown_autocomplete' ), 10, 2 );
// Rebuild stock status in all products with _out_stock_threshold when we disable this setting.
add_action( 'updated_option', array( $this, 'rebuild_wc_stock_status_on_disable' ), 10, 3 );
// Sometimes the paid date was not being set by WC when changing the status to completed.
add_action( 'woocommerce_order_status_completed', array( $this, 'maybe_save_paid_date' ), 10, 2 );
// Clean up the ATUM data when a product is deleted from database.
add_action( 'woocommerce_delete_product', array( $this, 'after_delete_product' ) );
add_action( 'woocommerce_delete_product_variation', array( $this, 'after_delete_product' ) );
// Save the ATUM product data for all the variations when created from attibutes.
add_action( 'product_variation_linked', array( $this, 'save_variation_atum_data' ) );
}
/**
* Register the global hooks
*
* @since 1.3.8.2
*/
public function register_global_hooks() {
// Save the date when any product goes out of stock.
add_action( 'woocommerce_product_set_stock', array( $this, 'record_out_of_stock_date' ), 20 );
// Set the stock decimals setting globally.
add_action( 'init', array( $this, 'stock_decimals' ), 11 );
// Delete the views' transients after changing the stock of any product.
add_action( 'woocommerce_product_set_stock', array( $this, 'delete_transients' ) );
add_action( 'woocommerce_variation_set_stock', array( $this, 'delete_transients' ) );
// Add out_stock_threshold hooks if required.
if ( 'yes' === Helpers::get_option( 'out_stock_threshold', 'no' ) ) {
add_action( 'woocommerce_product_set_stock', array( $this, 'maybe_change_stock_threshold' ) );
add_action( 'woocommerce_variation_set_stock', array( $this, 'maybe_change_stock_threshold' ) );
// woocommerce_variation_set_stock doesn't fires properly when updating from backend, so we need to change status for variations after save.
add_action( 'woocommerce_save_product_variation', array( $this, 'maybe_change_variation_stock_status' ), 10, 2 );
add_action( 'woocommerce_process_product_meta', array( $this, 'add_stock_status_threshold' ), 19 );
add_action( 'woocommerce_process_product_meta', array( $this, 'remove_stock_status_threshold' ), 21 );
add_action( 'atum/product_data/before_save_product_meta_boxes', array( $this, 'add_stock_status_threshold' ) );
add_action( 'atum/product_data/after_save_product_meta_boxes', array( $this, 'remove_stock_status_threshold' ) );
add_action( 'atum/product_data/before_save_product_variation_meta_boxes', array( $this, 'add_stock_status_threshold' ) );
add_action( 'atum/product_data/after_save_product_variation_meta_boxes', array( $this, 'remove_stock_status_threshold' ) );
}
// Save the orders-related data every time an order is saved.
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'save_order_items_props' ), PHP_INT_MAX, 2 );
// Recalculate the ATUM props for products within ATUM Orders, every time an ATUM Order is moved or restored from trash.
add_action( 'trashed_post', array( $this, 'maybe_save_order_items_props' ) );
add_action( 'untrashed_post', array( $this, 'maybe_save_order_items_props' ) );
}
/**
* Enqueue the ATUM admin scripts
*
* @since 1.4.1
*
* @param string $hook
*/
public function enqueue_scripts( $hook ) {
$post_type = get_post_type();
if ( 'product' === $post_type && in_array( $hook, [ 'post.php', 'post-new.php' ], TRUE ) ) {
// Enqueue styles.
wp_register_style( 'sweetalert2', ATUM_URL . 'assets/css/vendor/sweetalert2.min.css', array(), ATUM_VERSION );
wp_register_style( 'switchery', ATUM_URL . 'assets/css/vendor/switchery.min.css', array(), ATUM_VERSION );
wp_register_style( 'atum-product-data', ATUM_URL . 'assets/css/atum-product-data.css', array( 'switchery', 'sweetalert2' ), ATUM_VERSION );
wp_enqueue_style( 'atum-product-data' );
// Enqueue scripts.
wp_register_script( 'sweetalert2', ATUM_URL . 'assets/js/vendor/sweetalert2.min.js', array(), ATUM_VERSION, TRUE );
Helpers::maybe_es6_promise();
wp_register_script( 'atum-product-data', ATUM_URL . 'assets/js/build/atum-product-data.js', array( 'jquery', 'sweetalert2' ), ATUM_VERSION, TRUE );
wp_localize_script( 'atum-product-data', 'atumProductData', array(
'areYouSure' => __( 'Are you sure?', ATUM_TEXT_DOMAIN ),
'continue' => __( 'Yes, Continue', ATUM_TEXT_DOMAIN ),
'cancel' => __( 'Cancel', ATUM_TEXT_DOMAIN ),
'success' => __( 'Success!', ATUM_TEXT_DOMAIN ),
'error' => __( 'Error!', ATUM_TEXT_DOMAIN ),
'nonce' => wp_create_nonce( 'atum-product-data-nonce' ),
'isOutStockThresholdEnabled' => Helpers::get_option( 'out_stock_threshold', 'no' ),
'outStockThresholdProductTypes' => Globals::get_product_types_with_stock(),
) );
wp_enqueue_script( 'atum-product-data' );
}
}
/**
* Add set min quantities script to WC orders
*
* @since 1.4.18
*
* @param \WC_Order $order
*/
public function wc_orders_min_qty( $order ) {
$step = Helpers::get_input_step();
?>
get_type(), array_diff( Globals::get_inheritable_product_types(), [ 'grouped' ] ), TRUE )
) {
// Get the variations within the variable.
$variations = $the_product->get_children();
$stock_status = 'outofstock';
$stock_text = esc_attr__( 'Out of stock', ATUM_TEXT_DOMAIN );
$stock_html = '';
if ( ! empty( $variations ) ) {
$stock_html = ' (';
foreach ( $variations as $variation_id ) {
$variation_product = wc_get_product( $variation_id ); // We don't need to use ATUM models here.
$variation_stock = is_null( $variation_product->get_stock_quantity() ) ? 'X' : $variation_product->get_stock_quantity();
$variation_status = $variation_product->get_stock_status();
$style = 'color:#a44';
switch ( $variation_status ) {
case 'instock':
$stock_status = 'instock';
$stock_text = esc_attr__( 'In stock', ATUM_TEXT_DOMAIN );
$style = 'color:#7ad03a';
break;
case 'onbackorder':
if ( 'instock' !== $stock_status ) {
$stock_status = 'onbackorder';
$stock_text = esc_attr__( 'On backorder', ATUM_TEXT_DOMAIN );
}
$style = 'color:#eaa600';
break;
}
$stock_html .= sprintf( '%s, ', $style, $variation_stock );
}
$stock_html = substr( $stock_html, 0, -2 ) . ')';
}
$stock_html = "$stock_text" . $stock_html;
}
return $stock_html;
}
/**
* Add the location to the items table in WC orders
*
* @since 1.3.3
*
* @param \WC_Order $wc_order
*/
public function wc_order_add_location_column_header( $wc_order ) {
?>
|
get_type() ? $product->get_parent_id() : $product->get_id();
$locations = wc_get_product_terms( $product_id, Globals::PRODUCT_LOCATION_TAXONOMY, array( 'fields' => 'names' ) );
$locations_list = ! empty( $locations ) ? implode( ', ', $locations ) : '–';
}
?>
>
|
managing_stock() && in_array( $product->get_type(), Globals::get_product_types() ) ) {
// Reload the product using the ATUM data models.
$product = Helpers::get_atum_product( $product );
// Do not record the date to products not controlled by ATUM.
if ( Helpers::is_atum_controlling_stock( $product ) ) {
$current_stock = $product->get_stock_quantity();
$out_stock_date = NULL;
if ( ! $current_stock ) {
$out_stock_date = Helpers::date_format( current_time( 'timestamp' ), TRUE, TRUE );
}
/* @noinspection PhpUndefinedMethodInspection */
$product->set_out_stock_date( $out_stock_date );
/* @noinspection PhpUndefinedMethodInspection */
$product->save_atum_data();
}
AtumCache::delete_transients();
}
}
/**
* Delete the ATUM transients after the product stock changes
*
* @since 0.1.5
*
* @param \WC_Product $product The product.
*/
public function delete_transients( $product ) {
AtumCache::delete_transients();
}
/**
* Set the stock decimals
*
* @since 1.3.8.2
*/
public function stock_decimals() {
Globals::set_stock_decimals( Helpers::get_option( 'stock_quantity_decimals', 0 ) );
// Maybe allow decimals for WC products' stock quantity.
if ( Globals::get_stock_decimals() > 0 ) {
// Add step value to the quantity field (WC default = 1).
add_filter( 'woocommerce_quantity_input_step', array( $this, 'stock_quantity_input_atts' ), 10, 2 );
// Removes the WooCommerce filter, that is validating the quantity to be an int.
remove_filter( 'woocommerce_stock_amount', 'intval' );
// Replace the above filter with a custom one that validates the quantity to be a int or float and applies rounding.
add_filter( 'woocommerce_stock_amount', array( $this, 'round_stock_quantity' ) );
// Customise the "Add to Cart" message to allow decimals in quantities.
add_filter( 'wc_add_to_cart_message_html', array( $this, 'add_to_cart_message' ), 10, 2 );
// Add custom decimal quantities to order add products.
add_action( 'woocommerce_order_item_add_line_buttons', array( $this, 'wc_orders_min_qty' ) );
}
}
/**
* Set min and step value for the stock quantity input number field (WC default = 1)
*
* @since 1.3.4
*
* @param int $value
* @param \WC_Product $product
*
* @return float|int
*/
public function stock_quantity_input_atts( $value, $product ) {
if ( doing_filter( 'woocommerce_quantity_input_min' ) && 0 === $value ) {
return $value;
}
return Helpers::get_input_step();
}
/**
* Customise the "Add to cart" messages to allow decimal places
*
* @since 1.3.4.1
*
* @param string $message
* @param int|array $products
*
* @return string
*/
public function add_to_cart_message( $message, $products ) {
$titles = array();
$count = 0;
foreach ( $products as $product_id => $qty ) {
/* translators: the product title */
$titles[] = ( 1 != $qty ? round( floatval( $qty ), Globals::get_stock_decimals() ) . ' × ' : '' ) . sprintf( _x( '“%s”', 'Item name in quotes', ATUM_TEXT_DOMAIN ), wp_strip_all_tags( get_the_title( $product_id ) ) ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
$count += $qty;
}
$titles = array_filter( $titles );
/* translators: the titles of products added to the cart */
$added_text = sprintf( _n( '%s has been added to your cart.', '%s have been added to your cart.', $count, ATUM_TEXT_DOMAIN ), wc_format_list_of_items( $titles ) );
// Output success messages.
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
$return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wc_get_raw_referer() ? wp_validate_redirect( wc_get_raw_referer(), FALSE ) : wc_get_page_permalink( 'shop' ) );
$message = sprintf( '%s %s', esc_url( $return_to ), esc_html__( 'Continue shopping', ATUM_TEXT_DOMAIN ), esc_html( $added_text ) );
}
else {
$message = sprintf( '%s %s', esc_url( wc_get_page_permalink( 'cart' ) ), esc_html__( 'View cart', ATUM_TEXT_DOMAIN ), esc_html( $added_text ) );
}
return $message;
}
/**
* Hook update_options. If we update atum_settings, we check if out_stock_threshold == no.
* Then, if we have any out_stock_threshold meta, rebuild that product to update the stock_status if required
*
* @since 1.4.10
*
* @param string $option_name
* @param array $old_value
* @param array $option_value
*/
public function rebuild_wc_stock_status_on_disable( $option_name, $old_value, $option_value ) {
if (
Settings::OPTION_NAME === $option_name && isset( $option_value['out_stock_threshold'] ) &&
'no' === $option_value['out_stock_threshold'] && Helpers::is_any_out_stock_threshold_set()
) {
Helpers::force_rebuild_stock_status( NULL, FALSE, TRUE );
}
}
/**
* Firefox fix to not preserve the dropdown
*
* @since 1.4.1
*
* @param string $dropdown
* @param array $args
*
* @return string
*/
public function set_dropdown_autocomplete( $dropdown, $args ) {
if ( 'product_cat' === $args['name'] ) {
$dropdown = str_replace( '