/** * WooCommerce Customer Functions * * Functions for customers. * * @package WooCommerce\Functions * @version 2.2.0 */ use Automattic\WooCommerce\Enums\OrderInternalStatus; use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore; use Automattic\WooCommerce\Internal\Utilities\Users; use Automattic\WooCommerce\Utilities\OrderUtil; defined( 'ABSPATH' ) || exit; /** * Prevent any user who cannot 'edit_posts' (subscribers, customers etc) from seeing the admin bar. * * Note: get_option( 'woocommerce_lock_down_admin', true ) is a deprecated option here for backwards compatibility. Defaults to true. * * @param bool $show_admin_bar If should display admin bar. * @return bool */ function wc_disable_admin_bar( $show_admin_bar ) { /** * Controls whether the WooCommerce admin bar should be disabled. * * @since 3.0.0 * * @param bool $enabled */ if ( apply_filters( 'woocommerce_disable_admin_bar', true ) && ! ( current_user_can( 'edit_posts' ) || current_user_can( 'manage_woocommerce' ) ) ) { $show_admin_bar = false; } return $show_admin_bar; } add_filter( 'show_admin_bar', 'wc_disable_admin_bar', 10, 1 ); // phpcs:ignore WordPress.VIP.AdminBarRemoval.RemovalDetected if ( ! function_exists( 'wc_create_new_customer' ) ) { /** * Create a new customer. * * @since 9.4.0 Moved woocommerce_registration_error_email_exists filter to the shortcode checkout class. * @since 9.4.0 Removed handling for generating username/password based on settings--this is consumed at form level. Here, if data is missing it will be generated. * * @param string $email Customer email. * @param string $username Customer username. * @param string $password Customer password. * @param array $args List of arguments to pass to `wp_insert_user()`. * @return int|WP_Error Returns WP_Error on failure, Int (user ID) on success. */ function wc_create_new_customer( $email, $username = '', $password = '', $args = array() ) { if ( empty( $email ) || ! is_email( $email ) ) { return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'woocommerce' ) ); } if ( email_exists( $email ) ) { return new WP_Error( 'registration-error-email-exists', sprintf( // Translators: %s Email address. esc_html__( 'An account is already registered with %s. Please log in or use a different email address.', 'woocommerce' ), esc_html( $email ) ) ); } if ( empty( $username ) ) { $username = wc_create_new_customer_username( $email, $args ); } $username = sanitize_user( $username ); if ( empty( $username ) || ! validate_username( $username ) ) { return new WP_Error( 'registration-error-invalid-username', __( 'Please provide a valid account username.', 'woocommerce' ) ); } if ( username_exists( $username ) ) { return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'woocommerce' ) ); } // Handle password creation. $password_generated = false; if ( empty( $password ) ) { $password = wp_generate_password(); $password_generated = true; } if ( empty( $password ) ) { return new WP_Error( 'registration-error-missing-password', __( 'Please create a password for your account.', 'woocommerce' ) ); } // Use WP_Error to handle registration errors. $errors = new WP_Error(); /** * Fires before a customer account is registered. * * This hook fires before customer accounts are created and passes the form data (username, email) and an array * of errors. * * This could be used to add extra validation logic and append errors to the array. * * @since 7.2.0 * * @internal Matches filter name in WooCommerce core. * * @param string $username Customer username. * @param string $user_email Customer email address. * @param \WP_Error $errors Error object. */ do_action( 'woocommerce_register_post', $username, $email, $errors ); /** * Filters registration errors before a customer account is registered. * * This hook filters registration errors. This can be used to manipulate the array of errors before * they are displayed. * * @since 7.2.0 * * @internal Matches filter name in WooCommerce core. * * @param \WP_Error $errors Error object. * @param string $username Customer username. * @param string $user_email Customer email address. * @return \WP_Error */ $errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $email ); if ( is_wp_error( $errors ) && $errors->get_error_code() ) { return $errors; } // Merged passed args with sanitized username, email, and password. $customer_data = array_merge( $args, array( 'user_login' => $username, 'user_pass' => $password, 'user_email' => $email, 'role' => 'customer', ) ); /** * Filters customer data before a customer account is registered. * * This hook filters customer data. It allows user data to be changed, for example, username, password, email, * first name, last name, and role. * * @since 7.2.0 * * @param array $customer_data An array of customer (user) data. * @return array */ $new_customer_data = apply_filters( 'woocommerce_new_customer_data', wp_parse_args( $customer_data, array( 'first_name' => '', 'last_name' => '', 'source' => 'unknown', ) ) ); $customer_id = wp_insert_user( $new_customer_data ); if ( is_wp_error( $customer_id ) ) { return $customer_id; } // Set account flag to remind customer to update generated password. if ( $password_generated ) { update_user_option( $customer_id, 'default_password_nag', true, true ); } /** * Fires after a customer account has been registered. * * This hook fires after customer accounts are created and passes the customer data. * * @since 7.2.0 * * @internal Matches filter name in WooCommerce core. * * @param integer $customer_id New customer (user) ID. * @param array $new_customer_data Array of customer (user) data. * @param string $password_generated The generated password for the account. */ do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated ); return $customer_id; } } /** * Create a unique username for a new customer. * * @since 3.6.0 * @param string $email New customer email address. * @param array $new_user_args Array of new user args, maybe including first and last names. * @param string $suffix Append string to username to make it unique. * @return string Generated username. */ function wc_create_new_customer_username( $email, $new_user_args = array(), $suffix = '' ) { $username_parts = array(); if ( isset( $new_user_args['first_name'] ) ) { $username_parts[] = sanitize_user( $new_user_args['first_name'], true ); } if ( isset( $new_user_args['last_name'] ) ) { $username_parts[] = sanitize_user( $new_user_args['last_name'], true ); } // Remove empty parts. $username_parts = array_filter( $username_parts ); // If there are no parts, e.g. name had unicode chars, or was not provided, fallback to email. if ( empty( $username_parts ) ) { $email_parts = explode( '@', $email ); $email_username = $email_parts[0]; // Exclude common prefixes. if ( in_array( $email_username, array( 'sales', 'hello', 'mail', 'contact', 'info', ), true ) ) { // Get the domain part. $email_username = $email_parts[1]; } $username_parts[] = sanitize_user( $email_username, true ); } $username = wc_strtolower( implode( '.', $username_parts ) ); if ( $suffix ) { $username .= $suffix; } /** * WordPress 4.4 - filters the list of blocked usernames. * * @since 3.7.0 * @param array $usernames Array of blocked usernames. */ $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); // Stop illegal logins and generate a new random username. if ( in_array( strtolower( $username ), array_map( 'strtolower', $illegal_logins ), true ) ) { $new_args = array(); /** * Filter generated customer username. * * @since 3.7.0 * @param string $username Generated username. * @param string $email New customer email address. * @param array $new_user_args Array of new user args, maybe including first and last names. * @param string $suffix Append string to username to make it unique. */ $new_args['first_name'] = apply_filters( 'woocommerce_generated_customer_username', 'woo_user_' . zeroise( wp_rand( 0, 9999 ), 4 ), $email, $new_user_args, $suffix ); return wc_create_new_customer_username( $email, $new_args, $suffix ); } if ( username_exists( $username ) ) { // Generate something unique to append to the username in case of a conflict with another user. $suffix = '-' . zeroise( wp_rand( 0, 9999 ), 4 ); return wc_create_new_customer_username( $email, $new_user_args, $suffix ); } /** * Filter new customer username. * * @since 3.7.0 * @param string $username Customer username. * @param string $email New customer email address. * @param array $new_user_args Array of new user args, maybe including first and last names. * @param string $suffix Append string to username to make it unique. */ return apply_filters( 'woocommerce_new_customer_username', $username, $email, $new_user_args, $suffix ); } /** * Login a customer (set auth cookie and set global user object). * * @param int $customer_id Customer ID. */ function wc_set_customer_auth_cookie( $customer_id ) { wp_set_current_user( $customer_id ); wp_set_auth_cookie( $customer_id, true ); // Update session. if ( is_callable( array( WC()->session, 'init_session_cookie' ) ) ) { WC()->session->init_session_cookie(); } } /** * Get past orders (by email) and update them. * * @param int $customer_id Customer ID. * @return int */ function wc_update_new_customer_past_orders( $customer_id ) { $linked = 0; $complete = 0; $customer = get_user_by( 'id', absint( $customer_id ) ); $customer_orders = wc_get_orders( array( 'limit' => -1, 'customer' => array( array( 0, $customer->user_email ) ), 'return' => 'ids', ) ); if ( ! empty( $customer_orders ) ) { foreach ( $customer_orders as $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { continue; } $order->set_customer_id( $customer->ID ); $order->save(); if ( $order->has_downloadable_item() ) { $data_store = WC_Data_Store::load( 'customer-download' ); $data_store->delete_by_order_id( $order->get_id() ); wc_downloadable_product_permissions( $order->get_id(), true ); } do_action( 'woocommerce_update_new_customer_past_order', $order_id, $customer ); if ( $order->get_status() === OrderInternalStatus::COMPLETED ) { ++$complete; } ++$linked; } } if ( $complete ) { update_user_meta( $customer_id, 'paying_customer', 1 ); Users::update_site_user_meta( $customer_id, 'wc_order_count', '' ); Users::update_site_user_meta( $customer_id, 'wc_money_spent', '' ); Users::delete_site_user_meta( $customer_id, 'wc_last_order' ); } return $linked; } /** * Order payment completed - This is a paying customer. * * @param int $order_id Order ID. */ function wc_paying_customer( $order_id ) { $order = wc_get_order( $order_id ); $customer_id = $order->get_customer_id(); if ( $customer_id > 0 && 'shop_order_refund' !== $order->get_type() ) { $customer = new WC_Customer( $customer_id ); if ( ! $customer->get_is_paying_customer() ) { $customer->set_is_paying_customer( true ); $customer->save(); } } } add_action( 'woocommerce_payment_complete', 'wc_paying_customer' ); add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' ); /** * Checks if a user (by email or ID or both) has bought an item. * * @param string $customer_email Customer email to check. * @param int $user_id User ID to check. * @param int $product_id Product ID to check. * @return bool */ function wc_customer_bought_product( $customer_email, $user_id, $product_id ) { global $wpdb; $result = apply_filters( 'woocommerce_pre_customer_bought_product', null, $customer_email, $user_id, $product_id ); if ( null !== $result ) { return $result; } /** * Whether to use lookup tables - it can optimize performance, but correctness depends on the frequency of the AS job. * * @since 9.7.0 * * @param bool $enabled * @param string $customer_email Customer email to check. * @param int $user_id User ID to check. * @param int $product_id Product ID to check. * @return bool */ $use_lookup_tables = apply_filters( 'woocommerce_customer_bought_product_use_lookup_tables', false, $customer_email, $user_id, $product_id ); $transient_name = 'wc_customer_bought_product_' . md5( $customer_email . $user_id . $use_lookup_tables ); if ( $use_lookup_tables ) { // Lookup tables get refreshed along with the `woocommerce_reports` transient version. $transient_version = WC_Cache_Helper::get_transient_version( 'woocommerce_reports' ); } else { $transient_version = WC_Cache_Helper::get_transient_version( 'orders' ); } $transient_value = get_transient( $transient_name ); if ( isset( $transient_value['value'], $transient_value['version'] ) && $transient_value['version'] === $transient_version ) { $result = $transient_value['value']; } else { $customer_data = array( $user_id ); if ( $user_id ) { $user = get_user_by( 'id', $user_id ); if ( isset( $user->user_email ) ) { $customer_data[] = $user->user_email; } } if ( is_email( $customer_email ) ) { $customer_data[] = $customer_email; } $customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) ); $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() ); if ( count( $customer_data ) === 0 ) { return false; } if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { $statuses = array_map( function ( $status ) { return "wc-$status"; }, $statuses ); $order_table = OrdersTableDataStore::get_orders_table_name(); $user_id_clause = ''; if ( $user_id ) { $user_id_clause = 'OR o.customer_id = ' . absint( $user_id ); } if ( $use_lookup_tables ) { // HPOS: yes, Lookup table: yes. $sql = " SELECT DISTINCT product_or_variation_id FROM ( SELECT CASE WHEN product_id != 0 THEN product_id ELSE variation_id END AS product_or_variation_id FROM {$wpdb->prefix}wc_order_product_lookup lookup INNER JOIN $order_table AS o ON lookup.order_id = o.ID WHERE o.status IN ('" . implode( "','", $statuses ) . "') AND ( o.billing_email IN ('" . implode( "','", $customer_data ) . "') $user_id_clause ) ) AS subquery WHERE product_or_variation_id != 0 "; } else { // HPOS: yes, Lookup table: no. $sql = " SELECT DISTINCT im.meta_value FROM $order_table AS o INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON o.id = i.order_id INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id WHERE o.status IN ('" . implode( "','", $statuses ) . "') AND im.meta_key IN ('_product_id', '_variation_id' ) AND im.meta_value != 0 AND ( o.billing_email IN ('" . implode( "','", $customer_data ) . "') $user_id_clause ) "; } $result = $wpdb->get_col( $sql ); } elseif ( $use_lookup_tables ) { // HPOS: no, Lookup table: yes. $result = $wpdb->get_col( " SELECT DISTINCT product_or_variation_id FROM ( SELECT CASE WHEN lookup.product_id != 0 THEN lookup.product_id ELSE lookup.variation_id END AS product_or_variation_id FROM {$wpdb->prefix}wc_order_product_lookup AS lookup INNER JOIN {$wpdb->posts} AS p ON p.ID = lookup.order_id INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) AND pm.meta_key IN ( '_billing_email', '_customer_user' ) AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' ) ) AS subquery WHERE product_or_variation_id != 0 " ); // WPCS: unprepared SQL ok. } else { // HPOS: no, Lookup table: no. // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared $result = $wpdb->get_col( " SELECT DISTINCT im.meta_value FROM {$wpdb->posts} AS p INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) AND pm.meta_key IN ( '_billing_email', '_customer_user' ) AND im.meta_key IN ( '_product_id', '_variation_id' ) AND im.meta_value != 0 AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' ) " ); // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared } $result = array_map( 'absint', $result ); $transient_value = array( 'version' => $transient_version, 'value' => $result, ); set_transient( $transient_name, $transient_value, DAY_IN_SECONDS * 30 ); } return in_array( absint( $product_id ), $result, true ); } /** * Checks if the current user has a role. * * @param string $role The role. * @return bool */ function wc_current_user_has_role( $role ) { return wc_user_has_role( wp_get_current_user(), $role ); } /** * Checks if a user has a role. * * @param int|\WP_User $user The user. * @param string $role The role. * @return bool */ function wc_user_has_role( $user, $role ) { if ( ! is_object( $user ) ) { $user = get_userdata( $user ); } if ( ! $user || ! $user->exists() ) { return false; } return in_array( $role, $user->roles, true ); } /** * Checks if a user has a certain capability. * * @param array $allcaps All capabilities. * @param array $caps Capabilities. * @param array $args Arguments. * * @return array The filtered array of all capabilities. */ function wc_customer_has_capability( $allcaps, $caps, $args ) { if ( isset( $caps[0] ) ) { switch ( $caps[0] ) { case 'view_order': $user_id = intval( $args[1] ); $order = wc_get_order( $args[2] ); if ( $order && $user_id === $order->get_user_id() ) { $allcaps['view_order'] = true; } break; case 'pay_for_order': $user_id = intval( $args[1] ); $order_id = isset( $args[2] ) ? $args[2] : null; // When no order ID, we assume it's a new order // and thus, customer can pay for it. if ( ! $order_id ) { $allcaps['pay_for_order'] = true; break; } $order = wc_get_order( $order_id ); if ( $order && ( $user_id === $order->get_user_id() || ! $order->get_user_id() ) ) { $allcaps['pay_for_order'] = true; } break; case 'order_again': $user_id = intval( $args[1] ); $order = wc_get_order( $args[2] ); if ( $order && $user_id === $order->get_user_id() ) { $allcaps['order_again'] = true; } break; case 'cancel_order': $user_id = intval( $args[1] ); $order = wc_get_order( $args[2] ); if ( $order && $user_id === $order->get_user_id() ) { $allcaps['cancel_order'] = true; } break; case 'download_file': $user_id = intval( $args[1] ); $download = $args[2]; if ( $download && $user_id === $download->get_user_id() ) { $allcaps['download_file'] = true; } break; } } return $allcaps; } add_filter( 'user_has_cap', 'wc_customer_has_capability', 10, 3 ); /** * Safe way of allowing shop managers restricted capabilities that will remove * access to the capabilities if WooCommerce is deactivated. * * @since 3.5.4 * @param bool[] $allcaps Array of key/value pairs where keys represent a capability name and boolean values * represent whether the user has that capability. * @param string[] $caps Required primitive capabilities for the requested capability. * @param array $args Arguments that accompany the requested capability check. * @param WP_User $user The user object. * @return bool[] */ function wc_shop_manager_has_capability( $allcaps, $caps, $args, $user ) { if ( wc_user_has_role( $user, 'shop_manager' ) ) { // @see wc_modify_map_meta_cap, which limits editing to customers. $allcaps['edit_users'] = true; } return $allcaps; } add_filter( 'user_has_cap', 'wc_shop_manager_has_capability', 10, 4 ); /** * Modify the list of editable roles to prevent non-admin adding admin users. * * @param array $roles Roles. * @return array */ function wc_modify_editable_roles( $roles ) { if ( is_multisite() && is_super_admin() ) { return $roles; } if ( ! wc_current_user_has_role( 'administrator' ) ) { unset( $roles['administrator'] ); if ( wc_current_user_has_role( 'shop_manager' ) ) { $shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); return array_intersect_key( $roles, array_flip( $shop_manager_editable_roles ) ); } } return $roles; } add_filter( 'editable_roles', 'wc_modify_editable_roles' ); /** * Modify capabilities to prevent non-admin users editing admin users. * * $args[0] will be the user being edited in this case. * * @param array $caps Array of caps. * @param string $cap Name of the cap we are checking. * @param int $user_id ID of the user being checked against. * @param array $args Arguments. * @return array */ function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) { if ( is_multisite() && is_super_admin() ) { return $caps; } switch ( $cap ) { case 'edit_user': case 'remove_user': case 'promote_user': case 'delete_user': if ( ! isset( $args[0] ) || $args[0] === $user_id ) { break; } elseif ( ! wc_current_user_has_role( 'administrator' ) ) { if ( wc_user_has_role( $args[0], 'administrator' ) ) { $caps[] = 'do_not_allow'; } elseif ( wc_current_user_has_role( 'shop_manager' ) ) { // Shop managers can only edit customer info. $userdata = get_userdata( $args[0] ); $shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment if ( property_exists( $userdata, 'roles' ) && ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) { $caps[] = 'do_not_allow'; } } } break; } return $caps; } add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 ); /** * Get customer download permissions from the database. * * @param int $customer_id Customer/User ID. * @return array */ function wc_get_customer_download_permissions( $customer_id ) { $data_store = WC_Data_Store::load( 'customer-download' ); return apply_filters( 'woocommerce_permission_list', $data_store->get_downloads_for_customer( $customer_id ), $customer_id ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } /** * Get customer available downloads. * * @param int $customer_id Customer/User ID. * @return array */ function wc_get_customer_available_downloads( $customer_id ) { $downloads = array(); $_product = null; $order = null; $file_number = 0; // Get results from valid orders only. $results = wc_get_customer_download_permissions( $customer_id ); if ( $results ) { foreach ( $results as $result ) { $order_id = intval( $result->order_id ); if ( ! $order || $order->get_id() !== $order_id ) { // New order. $order = wc_get_order( $order_id ); $_product = null; } // Make sure the order exists for this download. if ( ! $order ) { continue; } // Check if downloads are permitted. if ( ! $order->is_download_permitted() ) { continue; } $product_id = intval( $result->product_id ); if ( ! $_product || $_product->get_id() !== $product_id ) { // New product. $file_number = 0; $_product = wc_get_product( $product_id ); } // Check product exists and has the file. if ( ! $_product || ! $_product->exists() || ! $_product->has_file( $result->download_id ) ) { continue; } $download_file = $_product->get_file( $result->download_id ); // If the downloadable file has been disabled (it may be located in an untrusted location) then do not return it. if ( ! $download_file->get_enabled() ) { continue; } // Download name will be 'Product Name' for products with a single downloadable file, and 'Product Name - File X' for products with multiple files. // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment $download_name = apply_filters( 'woocommerce_downloadable_product_name', $download_file['name'], $_product, $result->download_id, $file_number ); $downloads[] = array( 'download_url' => add_query_arg( array( 'download_file' => $product_id, 'order' => $result->order_key, 'email' => rawurlencode( $result->user_email ), 'key' => $result->download_id, ), home_url( '/' ) ), 'download_id' => $result->download_id, 'product_id' => $_product->get_id(), 'product_name' => $_product->get_name(), 'product_url' => $_product->is_visible() ? $_product->get_permalink() : '', // Since 3.3.0. 'download_name' => $download_name, 'order_id' => $order->get_id(), 'order_key' => $order->get_order_key(), 'downloads_remaining' => $result->downloads_remaining, 'access_expires' => $result->access_expires, 'file' => array( 'name' => $download_file->get_name(), 'file' => $download_file->get_file(), ), ); ++$file_number; } } // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment return apply_filters( 'woocommerce_customer_available_downloads', $downloads, $customer_id ); } /** * Get total spent by customer. * * @param int $user_id User ID. * @return string */ function wc_get_customer_total_spent( $user_id ) { $customer = new WC_Customer( $user_id ); return $customer->get_total_spent(); } /** * Get total orders by customer. * * @param int $user_id User ID. * @return int */ function wc_get_customer_order_count( $user_id ) { $customer = new WC_Customer( $user_id ); return $customer->get_order_count(); } /** * Reset _customer_user on orders when a user is deleted. * * @param int $user_id User ID. */ function wc_reset_order_customer_id_on_deleted_user( $user_id ) { global $wpdb; if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { $order_table_ds = wc_get_container()->get( OrdersTableDataStore::class ); $order_table = $order_table_ds::get_orders_table_name(); $wpdb->update( $order_table, array( 'customer_id' => 0, 'date_updated_gmt' => current_time( 'mysql', true ), ), array( 'customer_id' => $user_id, ), array( '%d', '%s', ), array( '%d', ) ); } if ( ! OrderUtil::custom_orders_table_usage_is_enabled() || OrderUtil::is_custom_order_tables_in_sync() ) { $wpdb->update( $wpdb->postmeta, array( 'meta_value' => 0, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ), array( 'meta_key' => '_customer_user', //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $user_id, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ) ); } } add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' ); /** * Get review verification status. * * @param int $comment_id Comment ID. * @return bool */ function wc_review_is_from_verified_owner( $comment_id ) { $verified = get_comment_meta( $comment_id, 'verified', true ); return '' === $verified ? WC_Comments::add_comment_purchase_verification( $comment_id ) : (bool) $verified; } /** * Disable author archives for customers. * * @since 2.5.0 */ function wc_disable_author_archives_for_customers() { global $author; if ( is_author() ) { $user = get_user_by( 'id', $author ); if ( user_can( $user, 'customer' ) && ! user_can( $user, 'edit_posts' ) ) { wp_safe_redirect( wc_get_page_permalink( 'shop' ) ); exit; } } } add_action( 'template_redirect', 'wc_disable_author_archives_for_customers' ); /** * Hooks into the `profile_update` hook to set the user last updated timestamp. * * @since 2.6.0 * @param int $user_id The user that was updated. * @param array $old The profile fields pre-change. */ function wc_update_profile_last_update_time( $user_id, $old ) { wc_set_user_last_update_time( $user_id ); } add_action( 'profile_update', 'wc_update_profile_last_update_time', 10, 2 ); /** * Hooks into the update user meta function to set the user last updated timestamp. * * @since 2.6.0 * @param int $meta_id ID of the meta object that was changed. * @param int $user_id The user that was updated. * @param string $meta_key Name of the meta key that was changed. * @param mixed $_meta_value Value of the meta that was changed. */ function wc_meta_update_last_update_time( $meta_id, $user_id, $meta_key, $_meta_value ) { $keys_to_track = apply_filters( 'woocommerce_user_last_update_fields', array( 'first_name', 'last_name' ) ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment $update_time = in_array( $meta_key, $keys_to_track, true ) ? true : false; $update_time = 'billing_' === substr( $meta_key, 0, 8 ) ? true : $update_time; $update_time = 'shipping_' === substr( $meta_key, 0, 9 ) ? true : $update_time; if ( $update_time ) { wc_set_user_last_update_time( $user_id ); } } add_action( 'update_user_meta', 'wc_meta_update_last_update_time', 10, 4 ); /** * Sets a user's "last update" time to the current timestamp. * * @since 2.6.0 * @param int $user_id The user to set a timestamp for. */ function wc_set_user_last_update_time( $user_id ) { update_user_meta( $user_id, 'last_update', gmdate( 'U' ) ); } /** * Get customer saved payment methods list. * * @since 2.6.0 * @param int $customer_id Customer ID. * @return array */ function wc_get_customer_saved_methods_list( $customer_id ) { return apply_filters( 'woocommerce_saved_payment_methods_list', array(), $customer_id ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } /** * Get info about customer's last order. * * @since 2.6.0 * @param int $customer_id Customer ID. * @return WC_Order|bool Order object if successful or false. */ function wc_get_customer_last_order( $customer_id ) { $customer = new WC_Customer( $customer_id ); return $customer->get_last_order(); } /** * When a user is deleted in WordPress, delete corresponding WooCommerce data. * * @param int $user_id User ID being deleted. */ function wc_delete_user_data( $user_id ) { global $wpdb; // Clean up sessions. $wpdb->delete( $wpdb->prefix . 'woocommerce_sessions', array( 'session_key' => $user_id, ) ); // Revoke API keys. $wpdb->delete( $wpdb->prefix . 'woocommerce_api_keys', array( 'user_id' => $user_id, ) ); // Clean up payment tokens. $payment_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id ); foreach ( $payment_tokens as $payment_token ) { $payment_token->delete(); } } add_action( 'delete_user', 'wc_delete_user_data' ); /** * Store user agents. Used for tracker. * * @since 3.0.0 * @param string $user_login User login. * @param int|object $user User. */ function wc_maybe_store_user_agent( $user_login, $user ) { if ( 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) && user_can( $user, 'manage_woocommerce' ) ) { $admin_user_agents = array_filter( (array) get_option( 'woocommerce_tracker_ua', array() ) ); $admin_user_agents[] = wc_get_user_agent(); update_option( 'woocommerce_tracker_ua', array_unique( $admin_user_agents ), false ); } } add_action( 'wp_login', 'wc_maybe_store_user_agent', 10, 2 ); /** * Update logic triggered on login. * * @since 3.4.0 * @param string $user_login User login. * @param object $user User. */ function wc_user_logged_in( $user_login, $user ) { wc_update_user_last_active( $user->ID ); update_user_meta( $user->ID, '_woocommerce_load_saved_cart_after_login', 1 ); } add_action( 'wp_login', 'wc_user_logged_in', 10, 2 ); /** * Update when the user was last active. * * @since 3.4.0 */ function wc_current_user_is_active() { if ( ! is_user_logged_in() ) { return; } wc_update_user_last_active( get_current_user_id() ); } add_action( 'wp', 'wc_current_user_is_active', 10 ); /** * Set the user last active timestamp to now. * * @since 3.4.0 * @param int $user_id User ID to mark active. */ function wc_update_user_last_active( $user_id ) { if ( ! $user_id ) { return; } update_user_meta( $user_id, 'wc_last_active', (string) strtotime( gmdate( 'Y-m-d', time() ) ) ); } /** * Translate WC roles using the woocommerce textdomain. * * @since 3.7.0 * @param string $translation Translated text. * @param string $text Text to translate. * @param string $context Context information for the translators. * @param string $domain Text domain. Unique identifier for retrieving translated strings. * @return string */ function wc_translate_user_roles( $translation, $text, $context, $domain ) { // translate_user_role() only accepts a second parameter starting in WP 5.2. if ( version_compare( get_bloginfo( 'version' ), '5.2', '<' ) ) { return $translation; } if ( 'User role' === $context && 'default' === $domain && in_array( $text, array( 'Shop manager', 'Customer' ), true ) ) { return translate_user_role( $text, 'woocommerce' ); } return $translation; } add_filter( 'gettext_with_context', 'wc_translate_user_roles', 10, 4 ); Crazy Time Live Gambling Establishment Game & Free Of Charge Demo Bonus - Ravian Technologies

Exclusive OFF Exclusive OFF - We are also offering one month free customer support after completing the project

AI Powered, Well Reputed and Trusted Company for Your Successful Business

Crazy Time Live Gambling Establishment Game & Free Of Charge Demo Bonus

“Enjoy Crazy Time Outcomes, Stats & Live Stream

It offers recently gained huge popularity in Bangladesh because of it is thrilling games, lovely graphics, and thrilling features. For calculating out your feasible long-term profits, Crazy Time’s RTP (Return to Player) is crucial. For a are living game show-style online casino game, Crazy Time’s 96. 08% RTP is competitive. With this RTP, participants may anticipate acquiring 96. 08% of their bets back typically over an extended time frame.

  • Crazy Moment differs from additional casino games thanks” “in order to its smooth the usage of interactive benefit features, massive multipliers, and high-quality internet streaming.
  • It is usually important to keep in mind that using a system does not assure winning the game!
  • IOS users can enjoy Crazy Time directly from their particular devices with soft performance and easy navigation.
  • Another significant succeed came about on The fall of 8, 2022, furthermore within a Cash Search round, where players earned a total of 12, 500x.

It’s bursting together with colour and each and every colour represents some sort of different kind of” “succeed. There is a new blue 1x, the 2x segment will be yellow, the 5x the first is pink plus there is the purple 10x section. All of these money tiles will be interrupted by distinct special feature tiles which punters could land on to trigger bonuses. I adore chatting with the supplier along with other players during the downtime. It feels like coming to a real online casino, but from the particular comfort of my own home.

What Is The Rtp Of Crazy Time?

IOS users could enjoy Crazy Moment directly from their very own devices with clean performance and effortless navigation. The table above is up to date daily and shows real data on hit frequencies.”

  • Crazy Time offers multipliers that can rise to an amazing x25, 000, producing it one of the most profitable games in the market.
  • The idea is that you spot a bet around the number you believe the wheel is going to arrive at and receive cash when you succeed.
  • Cash Hunt is the interactive shooting gallery with 108 unique multipliers.
  • You can play slots, table games, survive casino, bingo, poker, and more at maza247.

If the particular standard multipliers carry out not exceed x10, then the twice multipliers and the prize rounds achieve unprecedented heights. For example, an x10 multiplier on the earning bet of a hundred units would outcome in a pay out of 1000 devices. Just imagine just how much money can be credited to typically the balance if you play at the optimum bets. This is without considering the add-ons, which could bring x in total. Information about the latest largest payouts will motivate you and motivate one to participate within this interactive betting show with actual prizes. Bangladeshi bettors regularly elect to enjoy Crazy Time, in addition to for good purpose crazy time app.

Overview Of Bonus Rounds

Bitcoin, Litecoin, USDT, and Ethereum are the cryptocurrencies that some on the web casinos accept. It is the better and the majority of convenient way of users who wants to make anonymous purchases and steer clear of traditional financial fees. You could view demo movies to find out how every Crazy Time reward round operates.

Mobile gaming and slot is now more and more trendy among on the web casino users. Thus, CrazyTime Live retained up with this specific trend by supplying a mobile video game version. When this bonus drops, the particular game’s host may take you powering the red front door within the right aspect with the stage. You will quickly realize an amazing world worthy of the particular greatest amusement parks, which has a huge wheel at its centre.

Crazy Time Tyre And Odds

Once you could have done this, you will be able to choose how much you want to bet on each and every spin of typically the wheel. You can easily then spin the particular wheel and expect that it gets on your section. The processing occasions and the transaction fees for every payment method change depending on typically the internet casino you pick to play. In most cases, e-wallets are the best option regarding lower transaction service fees and faster running times than charge or charge cards in addition to bank transfers.

  • Rajbet features a user-friendly program, a fair plus transparent system, along with a 24/7 customer support team.
  • Every spin offers a possibility to win big with multipliers including x2 to x25, 000.
  • In conclusion, Bangladeshi users could play exciting in addition to immersive casino games on Crazy Period Live.
  • 22bet is surely an online betting program that offers a wide range involving sports events, marketplaces, odds, and reside streams.
  • The video game offers a selection of games that will keep you engaged for hrs and is basic enjoyable to play.

The Outrageous Time history will be filled with dramatic moments where participants have landed the particular Crazy Time bonus with huge multipliers, reaching up to be able to 20, 000x. Online casinos regularly function these events, which usually” “help the game’s ongoing within popularity. Watch the particular thrilling spins and engaging gameplay unfold throughout real-time.

Cash Hunt

You could also access Dafabet’s companies through its mobile app and website. In recent many years, Crazy Time provides emerged as one of the most thrilling live casino at redbet games. It has developed some enormous payouts thanks to the captivating bonus rounds and multipliers. During the Coin Change, Cash Hunt, and Pachinko” “reward rounds, players possess won sums pounds that have changed their lives. These victories show the particular possible benefits participants can receive in addition to are frequently printed by the game’s official channels and even social websites platforms. However, many players believe that using betting strategies can enhance the chances involving success and a big win inside Crazy Time.

  • Users can share their very own opinions, predictions, in addition to insights on typically the game with the particular Krikya community.
  • The National Lottery Regulatory Percentage has” “presented Marvelbet a permit to do business in Nigeria.
  • Mostbet provides a minimal minimum deposit in addition to a high deposit bonus for new consumers.
  • One with the standout characteristics of Crazy Time is the high level of interaction it provides.

The Crazy Time sport is surely an online online game that allows gamers to win actual money. The game will be played by content spinning a wheel that has different sections, every with its own multiplier. If typically the wheel lands on your section, you are going to win the matching amount of money. If the wheel lands about a number portion that you’ve bet on, you win a corresponding payment based on typically the odds. However, typically the real magic occurs when the wheel stops on one from the bonus times.

Casino Game Payment Options

The gambling fun starts off with the selection of bets in several zones. The unique gaming experience is provided by bonus rounds, these kinds of as the Bonus Game, Cash Hunt, Coin Flip, and Pachinko. Take to be able to appreciate the active gameplay and rejuvenate your wallet with Bangladeshi taka. Dafabet can be a reputable online betting company that are operating in Asia and offers a selection of sports activities betting, online casino, casino, and arcade games. Dafabet features been in the since 2004 and is licensed simply by Curacao. Dafabet provides a secure plus convenient betting experience with competitive odds, quick payouts, and generous bonuses.

  • The funds will become credited to your current deposit almost quickly, allowing you to place your very first bet in Insane Time.
  • A big wheel with amazing multipliers will encompass you, and an individual will” “probably be the one to catch the x20000 multiplier.
  • They are allowing consumers to start enjoying Crazy Time Survive immediately.
  • When it truly is activated, gamers are presented along with a screen showing a red endroit and a azure coin.

Crazy Time, launched in July 2020, is really a beloved are living game show known for its unmatched excitement. With a new dynamic presenter and a vibrant facilities featuring a Fantasy Catcher-style money steering wheel, the overall game offers fun fun with the particular chance for huge wins. Its innovative gameplay and online elements have manufactured it a outstanding in” “the field of online entertainment, engaging audiences worldwide. This special feature has a fun, colourful background and displays a large wheel. At typically the start of the particular bonus round, you will have to select a flapper.

App Advantages And Installation Features

It is a wonderful hint, after which you can immediately start playing with regard to money, and quite successfully. Each of those features contributes to be able to a seamless video gaming experience tailored merely for you. By following actions, you’ll have uninterrupted entry to all the features Crazy Moment offers. A combination of bingo in addition to lottery games in which users purchase greeting cards with various quantities. If a user’s numbers match, they are going to earn a payout based on typically the number of balls drawn. The standard and reliable selections for funding your consideration or withdrawing your current wins.

  • One associated with the most participating and graphically gorgeous games on the market is Crazy Time Live, which in turn combines facets of a new game show using casino rules.
  • She manages in order to balance player views with business objectives in determining typically the games and internet casinos featured on typically the site.
  • The rarest mini-game is definitely” “Outrageous Time, with only one sector on the particular drum, which activates this choice.
  • With a assumptive RTP ranging coming from 94. 41% to be able to 96. 08%, Outrageous Time promises pleasure and substantial advantages.
  • However, players might still monitor present data if that fuels their curiosity.

It gives players a distinctive experience with its thrilling bonus rounds, large multipliers, and interactive factors. The Crazy Period app makes certain you never overlook” “the second of the motion, whether you’re playing on a desktop computer or a cell phone device. We be familiar with importance of having access to current information while playing Crazy Time. Our platform offers complete live statistics that will enable you in order to make informed judgements and strategize your bets effectively. You can track crucial metrics like the frequency of bonus times, the occurrence associated with specific numbers, in addition to the average payouts for different sections of the wheel.

The Legitimacy Of Crazy Moment Live

Hitting a double Coin Turn was super rewarding, and the high-fives in the chat made it even better. As someone who generally sticks to slots, I wasn’t sure about a survive game. The vitality through the dealer, the particular anticipation of the particular wheel, as well as the added bonus rounds…whew!

However, this is the slow option because that they typically take a few business days and nights to process. Though slower than others, they are a great option for consumers who wish to transfer significant sums of funds. The Crazy Time App is optimized for mobile products to ensure gamers enjoy the online game away from home without reducing its quality. You are faced with a big wall where 108 bet multipliers usually are shuffled. When the time runs out there, the symbols vanish and the multipliers hidden behind them are” “revealed. So, whether an individual are enthusiastic about learning Crazy Time Live or are the Bangladeshi player trying to explore the on-line gambling world, this particular guide covers an individual.

Crazy Time Bangladesh Game

The web host then goes to the top with the” “Pachinko and randomly droplets the luminous basketball between zones 4 and 13. This is another mini-game where one can bet involving $0. 10 plus $250 at the particular start of typically the Crazy Time online game. Choose one of these two gold coins and participate within a “Heads or Tails” game.

  • The game will be played by spinning a wheel that has different sections, each with its own multiplier.
  • Sofia likewise uses her qualifications in digital media to promote innovative content formats, providing an modern multimedia angle to casino opinions.
  • Mostplay is a fresh internet casino that aspires to give you the ideal gaming experience with regard to Bangladeshi players.
  • Cash Hunt is the pachinko-style game within which players could win multipliers simply by shooting at symbols on a main grid.

From its added bonus rounds to the incredible multipliers, Crazy Period redefines internet casino experiences. If the wheel stops on a bonus game segment, just players with lively bets advance to be able to the bonus round. The Top Slot machine adds to the excitement by providing added multipliers, having a highest of 50x.

How To Play Crazy Time

Only whether it is held for everyone in the news, then in your current favourite Bangladesh casino – just with regard to you. The” “design has been inside demand since 2020 when it was introduced to several gambling sites throughout the country. In the main sport, bets are recognized simultaneously on several regions of the tires. This increases the chance of achievement and activation associated with bonus rounds. One of the advantages of the recommended entertainment is that it is a live video game. Gamblers can observe high-quality broadcasts by simply choosing a dependable gambling establishment.

BetVisa is a new and innovative gambling online platform that suits the Bangladeshi marketplace. BetVisa offers the selection of casino games, wagering, rummy, and even other instant online games. BetVisa includes a user-friendly interface, a good plus honest system, plus a 24/7 customer care team. You can also enjoy a 300% bonus on your current first deposit and even 5 free rounds if you sign up at BetVisa. Parimatch is a leading on the web betting platform that offers many different sports activities, casino, and live games.

Testimonials About Crazy Time Live

The host climbs the stairs plus drops a puck from the leading of the wall structure. In case of the double, all multipliers are doubled plus the puck is released again. The video game offers a selection of games that will will keep you engaged for several hours and is basic enjoyable to enjoy. Crazy time are living stream has some thing to offer every person, whether you are usually just starting or even a seasoned person. Set up the bets and allow the autoplay function spin the tire automatically. When you obtain the Cash Hunt bonus, the sport takes you to some new screen using 108 random multipliers hiding behind icons.

  • It is the greatest and the majority of convenient means for customers who wants to be able to make anonymous transactions and steer clear of traditional banking fees.
  • Thanks to our own collaborations with plenty of online internet casinos, we are very happy to announce that you can find Monopoly Live all over the place!
  • Multipliers are a crucial function that can drastically increase your winnings.
  • CrazyGames is really a free browser gaming platform founded in 2014 by Raf Mertens.

You must check out the terms and even conditions of your respective chosen payment method ahead of making any purchase to avoid any kind of unexpected fees. The software is available regarding iOS users to download through the software Store. All an individual have to do is try to find the particular Crazy Time iphone app, click “Download, ” and it will certainly install itself. Experience the excitement as typically the puck falls directly into slots with various multipliers.

Understanding The Particular Rtp In Crazy Time

Crazy Period is a online game show where the real host is by your area 24/7. Please be aware that all of each of our partners only recognize real money video games on Crazy Time (and on most live games). Indeed, only spectators will be allowed, but no demo mode is available. A fortunate player secured an remarkable 25, 000X gamble multiplier” “during the Cash Hunt added bonus game on Dec 11, 2022, resulting in a win of €2, 815, 169. Crazy Time offers chances for major wins, with multipliers climbing to countless numbers and even tens regarding thousands of periods your bet.

  • When the wheel stops rotating, the player either wins or loses their bets.
  • In simple conditions, for every 100 units you wager, you can expect to get back 96 units more than Time.
  • An electric ball is decreased at the top of the reels, making its method down to the prizes.
  • The host climbs the stairs and drops a puck from the best of the wall.

Discover firsthand records of players which have embarked on their strategy voyage and emerged successful, sharing their experience and insights. Players can choose the the majority of convenient payment approach for Monopoly Live and other enjoyment. Installing on a good iOS device starts off with going to be able to the official online casino site and comes to an end with the physical appearance of a shortcut. The software does not generally demand special device requirements so that everyone is able to install it. Popular tags include car games, Minecraft, 2-player games, match a few games, and mahjong. With Crazy Period Tracker you can easily enjoy real-time stats and leads to one place.

Crazy Time Online Game Overview For Bangladesh

When the wheel stops on the Outrageous Time section, you can be transferred to a new room together with a wheel filled up with 64 randomly created multipliers. The coin flips automatically in addition to depending on which side it gets on, you will certainly be granted an additional multiplier. There are not any predefined multipliers, and they are generally chosen randomly prior to the bonus game. That is” “the reason why we respect almost all responsible gaming requirements on Crazy Some why we would like to raise attention among players about the dangers of gambling.

  • The Crazy Time live stream gives the thrill immediately to your system for those who else prefer to witness the action up shut.
  • Additionally, professional live dealers make your own gameplay engaging and brighten it up with their enjoyable talks.
  • You have understood that nearly all the potential of Insane Time is based on the particular bonus mini-games.
  • It can be multiplied even more in the event the multiplier tyre” “falls on the Gold coin Flip.
  • The Top Slot machine game adds to the particular excitement by providing extra multipliers, having a optimum of 50x.

With most these information, you will get a better odd of winning. Most online casinos don’t charge users for making deposits or withdrawals. However,” “a few payment providers may possibly charge fees for services.

Crazy Time Trial Video

Pachinko will be” “a benefit round that discloses a big crimson screen with awards listed at typically the bottom. An electronic ball is dropped at the top rated of the reels, making its way down to the prizes. An on the internet platform offering several cricket-related services, which includes live scores, information updates, and evaluation of cricket suits. It provides customers with real-time updates on the fits, including live results, commentary, and movie highlights. You will certainly find a crimson vertical wall with 16 boxes with the bottom. Random multipliers will suit in there, since well one or perhaps more “double” signs if you’re fortunate.

  • BetVisa provides a user friendly interface, a good and honest system, in addition to a 24/7 customer service team.
  • The online betting industry has become more and more popular as the years go by simply.
  • To get a very first look at our Evolution Monopoly Are living game, the content teams first would like to guide you action by step in order to start playing today.
  • Mostbet is familiar with the laws by Curacao while offering a wide range of betting options and markets.
  • For a are living game show-style on line casino game, Crazy Time’s 96. 08% RTP is competitive.
  • Players globally have won life-changing amounts thanks to substantial multipliers and added bonus rounds.

Crazy Period can be a well-known live dealer game produced by Evolution Gambling. It exists throughout almost all qualified online casinos throughout the world, including Winz. io. You will easily find the game in gambling platforms that cooperate with typically the software vendor. You have landed on the right online game show because our Pachinko mini-game is clearly in this kind of theme.

Play Monopoly Live: Find An Evolution Video Gaming Partner

Once players include all chosen a new different coloured flapper, the wheel may spin. When that stops, your reward will depend in which colour flapper you selected at the beginning regarding the bonus. A mini-game is brought on when the steering wheel lands on the bonus games portion. During these rounds, users can have got the opportunity in order to win additional prizes. There are four bonus rounds which often are Coin Switch, Cash Hunt, Pachinko and Crazy Time. The Crazy Moment live stream delivers the thrill directly to your system for those that want to witness the action up close up.

  • Take to be able to appreciate the interactive gameplay and replace your wallet along with Bangladeshi taka.
  • Once you might have done this particular, it will be easy to pick how much you need to bet on every spin of the particular wheel.
  • I love conntacting the supplier and also other players in the course of the downtime.
  • The gambling odds and payment ratios will vary based on the segment the particular user chooses to wager.
  • When you will get the Cash Quest bonus, the game takes you to some new screen using 108 random multipliers hiding behind symbols.

Mostbet is familiar with the laws by Curacao and offers a wide range of betting choices and markets. You can also take pleasure in live streams, video poker machines, TV games, plus more at Mostbet. Mostbet includes a lower minimum deposit in addition to a high deposit bonus for new consumers. One of the most captivating live casino at redbet games on typically the market at this time will be Crazy Time.

Scroll to Top
Scroll to Top
small_c_popup.png

Let's have a chat

Get A Quote