/** * 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 ); if ( $use_lookup_tables ) { // Lookup tables get refreshed along with the `woocommerce_reports` transient version (due to async processing). // With high orders placement rate, this caching here will be short-lived (suboptimal for BFCM/Christmas and busy stores in general). $cache_version = WC_Cache_Helper::get_transient_version( 'woocommerce_reports' ); } elseif ( '' === $customer_email && $user_id ) { // Optimized: for specific customers version with orders count (it's a user meta from in-memory populated datasets). // Best-case scenario for caching here, as it only depends on the customer orders placement rate. $cache_version = wc_get_customer_order_count( $user_id ); } else { // Fallback: create, update, and delete operations on orders clears caches and refreshes `orders` transient version. // With high orders placement rate, this caching here will be short-lived (suboptimal for BFCM/Christmas and busy stores in general). // For the core, no use-cases for this branch. Themes/extensions are still valid use-cases. $cache_version = WC_Cache_Helper::get_transient_version( 'orders' ); } $cache_group = 'orders'; $cache_key = 'wc_customer_bought_product_' . md5( $customer_email . '-' . $user_id . '-' . $use_lookup_tables ); $cache_value = wp_cache_get( $cache_key, $cache_group ); if ( isset( $cache_value['value'], $cache_value['version'] ) && $cache_value['version'] === $cache_version ) { $result = $cache_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 p.post_type = 'shop_order' 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 ); wp_cache_set( $cache_key, array( 'version' => $cache_version, 'value' => $result, ), $cache_group, MONTH_IN_SECONDS ); } 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 ); What Casino Game Gets The Best Odds? – Barter Up Now – Trade without Money
Loading…
  • ahtsham
  • July 9, 2025

What Casino Game Gets The Best Odds?

50 Best Payout Video Poker Machines Which Slot Machines Have The Best Payouts?

Ultimately, understanding slot machine odds in addition to payouts leads to responsible gambling. You know what the particular casino operators and slot designers realize. With that details, you can go walking into brick-and-mortar internet casinos (or visit online slot casinos) knowing it’s for enjoyment. Sometimes, you will encounter the slot machine that may be described as “loose” or “tight. ” This is certainly just one other way of talking about a game’s RTP. A loose slot machine pays out even more often in a increased percentage, while a tight machine comes with a lower RTP and even pays out fewer frequently.

  • Another important concept is to have got” “reasonable expectations.
  • Online casinos, just like a slot machine, has the payout percentage – RTP.
  • Making note of trends, key traumas, and matchups could help players discover some winnings upon a weekend of action.
  • What’s even more, you also will need to think about a slot’s variance, as games with lower unpredictability pay out more regularly, albeit smaller portions of money.
  • You can acquire these currencies totally free or purchase numismatic coins to earn bonuses of sweepstakes coins.

This is usually appealing to many players happy to take upon higher risks in exchange for successful larger, life-changing quantities. Before you start playing, it is usually best you decide on a new game with some sort of substantial RTP portion by looking at the particular RTP % supplied by the gambling establishment online. Since you will find literally thousands of machines to choose from, it is best you look with how to locate a good slot machine in any on line casino, no matter location and offerings. The best way to succeed at a on line casino is to know chances, RTP, and even house edge within order to locate the very best conditions.

Game Variety With Odds

Even when playing basic strategy in blackjack or maximizing free odds within the craps table, there may be nonetheless plenty of likelihood of losing. These are extremely simple wagers to generate and offer several odds of winning. Like other great game titles, there are some drawback wagers also. Stay apart from this awful bet since it will come with a huge house edge associated with 14. 36%! mostbet

  • However, slots come inside a vast variety of games, with a few having house ends below 1% in addition to others soaring to be able to over 15%.
  • Find a new blackjack strategy data to make the best choices.
  • It’s a no-brainer once you add in the convenience regarding playing online.
  • From this information we can conclude of which the best slot machines in terms associated with denomination are the $5, $25, and even $0. 05.
  • — The worst in the casino for participants, Three-Card Poker, 171 units that gained $125. 3 million and had some sort of win rate regarding 32. 18 percent.

In this case, the particular casino takes 5% of the bet in addition to reduces the prospective prize. Therefore, just about every possible result includes a certain probability attached with it. The RNG creates thousands regarding results per second based on the algorithm. When a new player hits “Spin, ” the RNG chooses the final result created while the outcome regarding the spin. Expanding reels can change the odds considerably and cluster compensates, like on Aztec Clusters, sees winning symbols pay out and about before being substituted with additional emblems.” “[newline]On average, Sligo games offer an RTP of around 97% and the RTP is the best option intended for assessing a Slingo game. For illustration, an RTP of 98% signifies that a player would obtain 97% of their bets back when they played above the set period.

How Sincere Slots Payout Percentage Is?

I spoken about volatility in more detail in precisely how to play on the internet slot machines guide, I advise all newcomers to read it. I am sure this information will be beneficial to you when choosing online online casino or slot equipment with best payouts. The come bar also functions as a pass series bet in the particular middle of a roll and provides exactly the same odds. These are great odds regarding players and present some real odds to win.

  • French Roulette is much more favorable with a new house edge of 1. 35%.
  • But it is important to appearance for when deciding on a game title is their RTP or go back to player percentage.
  • Yet, the state doesn’t ask them to publish slots payback since there’s no minimum RTP.
  • As a result, the outcome is largely determined by chance rather as compared to the player’s abilities.

Of course, these aren’t actually 50/50 gambling bets since the house develops” “in a edge to make money. Casinos help to make money at roulette by not spending out the odds of hitting specific numbers. For individuals betting on person numbers, the probabilities are 1 in 38 on the double-zero wheel (American style) and 1 within 37 on a single-zero wheel (European style). There is in fact zero house edge in the odds gamble, meaning players are certain to get paid the true likelihood of hitting of which number. House edge is the portion the house will certainly receive, usually, through every bet located. Every casino sport except a select number of has an edge for the property mostbet app download.

Checklist For Finding Slot Machines With The Best Odds Of Winning

When a online game designer makes a brand new slot, they must compute the effect of every rule, betting choice, and game function on the expected return. Free moves and multipliers affect a slot machine’s odds, just just like jackpot sizes do. Add all this up and you have the game’s payout percent, also known since the return to person. We’ll explain the reason why below, but gamers should know several quick facts regarding slot machine odds.

The increased RTP can be related to online casinos having much less overhead than brick-and-mortar properties. When you’re hunting for slot machines with the ideal odds of winning, head to the particular online casinos. Playtech’s Ugga Bugga will be a good game to begin with, since it offers normal payouts of fairly small amounts, while evidenced by the high RTP in addition to low variance. Yes, many online internet casinos offer free demonstrations of high-RTP slots, allowing you to test the video games before committing true money.

Best Casinos With Highest Position Payouts

If the slot machine passes the check out, it receives the corresponding certificate. Knowing your chances of winning throughout percentages is the most straightforward solution to find the online casino game with the particular best odds. This value is identified as the “Return to player”, or perhaps RTP, from the online game.

  • The better the particular odds, the much more likely that will outcome is usually to occur.
  • Instead, the real key strategy is getting slots with typically the best odds possible.
  • So, if you’re keen to match slot machine game games with typical table games, black jack is an excellent game in order to get started together with, particularly if you’re keen to minimize the house advantage.
  • If a game seemed to be certain to returning 98% to you personally, that would mean you’d lose every individual time.

At Slotsguy. com, online players enjoy exclusive bonuses, boosting your current chances and entertaining! Dive into a sea of possibilities and spin your own way to good results with our unparalleled online offers. Generally, a lot more money you need to expend to play, typically the better your possibilities of winning usually are.” “[newline]You may also possess better odds of winning smaller affiliate payouts than a goldmine prize. Winning blackjack takes luck along with a small amount of skill to know whenever to draw an additional card and if to stop. The seller relies as a lot on luck while the players carry out, so the chances of winning are usually pretty even. But if you would like to improve your odds of walking apart with additional money as compared to you went throughout with, you need to know which in turn games are the majority of likely to earn.

Which Casino Games Give You The Greatest Odds Of Successful?

For example, a slot” “having a 96% RTP will return, on typical, $96 for every single $100 wagered. The remaining percentage signifies the casino’s house edge. Slot equipment odds can be difficult to be able to understand for any kind of player who does not enjoy mathematics. While the ideas are basic, that they are not simple.

  • Furthermore, you’ll have a larger probability of getting away with house cash.
  • The higher a slot machine machine” “payout percentage is, the higher is it intended for players.
  • Slot devices from a film, tv show, or general pop lifestyle phenomenon are contractually obligated to shell out loyalties.
  • Therefore, just about every possible result has a certain probability mounted on it.

Also, look at the spend table, which displays how much each symbol is well worth like that, you realize which symbols usually are more lucrative and even whether there will be any wild credit cards. With over one hundred twenty, 000 slots around Nevada, vast array will be a lot in addition to distributed. Just FYI, the very best slot jackpot feature ever recorded seemed to be $39. 7 million in 2003 with Excalibur Casino. It’s a long-term calculate that improves your overall odds but doesn’t assure specific results.

Craps Odds

This is essential since the odds associated with winning on one spin and rewrite would be very reasonable – possibly countless numbers to one – however the likely payment after some time is much more useful. For example, the common blackjack game provides the player probabilities of 49% and the house 51%, meaning you’ve almost acquired an equal 50/50 shot at earning. Most platforms offer the possiblity to perform for free without having putting a single dime on the line. The 50/50-type bets offer gamers the slimmest chances and are merely a matter involving picking red/black or perhaps odd/even numbers.

  • The odds determine how significantly you can succeed and how most likely you happen to be to earn, so finding the particular best odds is vital.
  • Two versions of Online game King Video Online poker are available, yet our experts very recommend testing out the live dealer variations.
  • Essentially this gives the participant a higher possibility of winning because once the player has reached that will value, the slot machines has to pay.
  • This is because some slot developers provide casinos using several RTP options” “to choose from, resulting in adjustable payouts from online casino to casino.

This number is also termed as the return to player, or RTP. Casino gamblers who focus primarily upon scratch cards have much less muck in order to filter through. A craps table is definitely a craps desk in any online casino, blackjack is even more complex, several video games are similar. There’s a difference between not winning and even like a loser. You can also enjoy a online casino and accept of which it will run you some money in order to be there. After all, you’ll devote money if a person go to an amusement park, too.

Explore The Best Slots Across Top On The Web Casinos

Players will know these people shouldn’t rely upon slot machines to shell out the bills, and chasing losses is definitely never a good idea. These slot machine game machines combine clean volatility with a high return to be able to the player. Ultimately, these games provide you with the best odds involving winning when you’re playing slot devices in a casino. Before you start, know that none involving the casino video games offer good chances for players. No matter how well you plan, you might still lose money, so be sure to set up a price range before you begin and stick to it.

Remember, the higher the RTP, the particular more it pays out per $100 wagered on the machine. What’s a lot more, you also will need to consider a slot’s variance, as online games with lower volatility spend more regularly, albeit smaller quantities of money. If you’re struggling in order to find information about a new game’s RTP plus variance at an online casino, you can easily simply seek out exactly what you’re trying to find. For instance, you can type something like “Starburst RTP percentage” into Google and easily find that the game’s RTP is ninety six. 01%. As a person can see to sum up five games, different developers offer large RTP slots with various variances, providing something to suit” “most player preferences. Based on “Alice inside Wonderland, ” White-colored Rabbit Megaways has a RTP of 97. 72% and an impressive 248, 832 ways to win.

High Volatility

Helpfully, most on-line casinos publish this information in the slot machine game description that accompanies the game. If you’re looking to be able to get the most from your on-line slot experience in 2025, finding games with high RTP (Return to Player) rates can make a factor. Slots with the highest RTP give gamers better odds regarding convincing time, while a higher portion of wagers usually are returned to participants on average. This guide explores some of the best high-RTP slots” “from leading providers, assisting you find the many rewarding games obtainable. Understanding the Returning to Player (RTP) is crucial since it indicates the proportion of wagered funds a slot equipment will pay to players over time. A higher RTP means better probabilities of winning, as a result strategically choosing online games with high RTP can significantly impact your winnings in addition to extend your play.

  • Sometimes, you will come across some sort of slot machine that is described as “loose” or “tight. ” It is just an additional way of mentioning a game’s RTP.
  • Please remember that Slotsspot. apresentando doesn’t operate virtually any gambling services.
  • If you want to play free online slot machine games, look for games together with higher RTPs in order to maximize your chances of winning.
  • The likelihood of winning in any blackjack game depend on what regulations you’re playing simply by.
  • Most online internet casinos for real money offer the game titles we’ve discussed on this page.

No matter your preference, understanding RTPs and local insights may help you maximize your slot-playing experience. However, since slots are usually under strict regulations, it is harder to see exactly why gamblers firmly cling to the idea. Some say for the reason that internet casinos are flexible within adjusting” “payout percentages, but once more, it is always in a given controlled manner. To have a more profound understanding of odds and higher payouts in gambling establishment games, take some sort of look at each of our list of game titles with the best odds intended for a payout. By grasping these concepts, you can get a far more in-depth knowing of odds within games and select the best internet casinos according to your needs. This way, you won’t be waiting a long period between wins, and even you can come with an enjoyable online online casino experience of free on-line slots.

Where Can I Actually Sign Up Plus Play The Best Casino Games Online?

With frequent small wins, free spins, and a bonus game, this slot machine is excellent intended for long play classes lacking substantial risk. If the jackpot is bigger than the chances of hitting the jackpot, then a progressive slot can end up being a positive expectation game. Today, all of us provide a quick how-to guide on how slot machine game percentages work. This guideline also gives guidelines for finding high-payout slot machines. Read with the article beneath and you’ll” “shortly know the basics of slot machine payouts. And while slots aren’t actually the best wager when it comes to odds, playing online at very least gives players the better shot in getting some regarding their money-back.

— Ultimate Texas Hold-em, 177 units that won $188. 7 million together a win rate of twenty-two. 06 percent. — Roulette, 432 devices that won $460. 3 million plus had a win rate of nineteen. 6 percent. — Craps, 319 devices that won $467. 5 million and had a win charge of 16. sixty two percent. — Baccarat, 393 units that won $1. 488 billion and had a win price of 16. 40 percent. — Race books, 158 products that won $30. 4 million plus had a win rate of fifteen. 6 percent.

Slotsguy #1 Recommendation

It provides up quickly, which is why casinos make as very much money since they carry out. Casino games may well be “games involving chance, ” although that’s not completely accurate. Sure, you’re taking a possibility jointly hand or even spin, but always keep in mind that behind every game is an edge that makes sure that the prefer is definitely with the house.

The explanation to choose classics is because they had been designed for lower volatility. If your goal is to only benefit from the game with less chances involving losing so you carry out not care regarding huge bonuses next these ones usually are for you personally. Slot equipment get popular just if they are enjoyment and profitable. If you walk directly into a casino and see many people enjoying the classics like Wheel of Fortune and Buffalo Awesome, then you recognize you will help to make a few money from them.

Craps

With up in order to 100 free spins, Heidi’s Bier Haus provides you a opportunity to just take a seat and relax in addition to get to know the fun side associated with slots. Wheel regarding Fortune is some sort of popular progressive position game with increased payouts compared to penny slots. Fu Dao Le, in the other hand, includes both multiplier and progressive components to offer” “gamers 243 ways to be able to win with classic old-school Chinese symbolism.

  • Fortunately, the games these systems offer are subject matter to strict restrictions and cannot always be changed by on-line casinos.
  • For example, together with an equal variety of black and red-colored numbers – in addition to one green – you almost have got a 50/50 picture at winning an outdoor bet on typically the color of the winning number.
  • By the end, you’ll have as significantly of a leg up as you should against the house.

That offers gamblers a much better possibility of winning compared to the best slot machine machines in Las Vegas. For online players, the sky is usually the limit if looking for video games with a really good odds of winning. Players can easily often find typically the RTP directly upon the site, and lots of games will include an increased RTP compared to anything you’ll discover in land-based casinos. The two gambling establishment games that are hardest to succeed also are actually two of the most popular games to be able to play. They’re straightforward and require little to no skill, so a lot of people play, making lots of money for the casinos.

High Volatility Slots

Understanding these kinds of characteristics of position machines will provide you with typically the opportunity to learn how to pick the best payouts slots. Each slot game includes a given RTP, and it’s really crucial to recognize this metric before playing. Understanding payout percentages helps a gamer pick the particular online slot game with the greatest odds.

Like gambling, poker is offered being a seamlessly incorporated strategy to players about the BetMGM platform. The operator offers a nice holdem poker option with a lot of cash games and even tournament options. This type of wagering has a house edge of two. 7% (double-zero) and 2. 63% (single-zero). Betting more than one range can bring these percentages favoring the particular casino from more than 5% in order to as high since over 10% any time picking four amounts.

Baccarat Odds

The action of this specific generator is firmly controlled by regulatory bodies. He can win if this individual gets a seven or an 11 on the 1st roll. Any additional number, rolled by simply the shooter, becomes the “point. ” A shooter which misses over 1 point is disqualified. The Go back to Player (RTP) is a manifestation of how many of your wagers you are likely to see returned following a set number involving spins.

  • For instance, an RTP involving 98% ensures that the player would get 97% of their very own bets back in case they played over the set period.
  • Go for large volatility machines in case you have a larger bankroll, so that will it may become some sort of higher reward which mitigates the threat.
  • Even though penny slots have typically the worst win percentages, they are cheaper to play.
  • High volatility games take things in the opposite course.
  • Knowing the chance for winning in percentages is the particular most straightforward method to find the gambling establishment game with the particular best odds.

“These days, there are lots of companies that produce s. Almost every developer in the market generates online slot machines. However, there are regarding 20 well-known manufacturers, the slots of which are typically the most popular among gamers. As I previously said, to perform for real cash, it is better to choose slots together with a payout portion of at minimum 95% because these people are slot machines with a really good odds associated with winning. I feel sure that in case you have queries regarding slot machine game affiliate payouts, now they have passed away. If you need to find and even play slot machines together with highest payouts for real money, then you certainly need to always be well versed within slot machines payment percentages.

Trends Affecting Slot Machine Game Rtps In 2025

Finding the RTP intended for games can always be a challenge in its own right; I’ll show you exactly why. But when every single game has the different group of affiliate payouts and odds, items become complicated. UpswingPoker. com recommends enjoying at night, if there are frequently more recreational players around and any time the drinks possess been flowing for quite a while. You can boost the payout—but lower your odds—by betting on specific numbers or perhaps ranges of quantities (like “1 to 12” or “1 to 18”).

High volatility provides much larger numbers of the award, but higher hazards, and vice versa. In fact, this can exceed 100%, but this will be a couple of expertise. In offline casinos, roulette takes typically the form of some sort of wheel established about a table – the so-called gambling area or design. The wheel consists of pockets placed circle-wise and marked along with a number each.

Top