Current File : /home/bdmcricketindia.in/public_html/wp-includes/class-wp-meta-query.php
<?php
/**
 * Meta API: WP_Meta_Query class
 *
 * @package WordPress
 * @subpackage Meta
 * @since 4.4.0
 */

/**
 * Core class used to implement meta queries for the Meta API.
 *
 * Used for generating SQL clauses that filter a primary query according to metadata keys and values.
 *
 * WP_Meta_Query is a helper that allows primary query classes, such as WP_Query and WP_User_Query,
 *
 * to filter their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached
 * to the primary SQL query string.
 *
 * @since 3.2.0
 */
#[AllowDynamicProperties]
class WP_Meta_Query {
	/**
	 * Array of metadata queries.
	 *
	 * See WP_Meta_Query::__construct() for information on meta query arguments.
	 *
	 * @since 3.2.0
	 * @var array
	 */
	public $queries = array();

	/**
	 * The relation between the queries. Can be one of 'AND' or 'OR'.
	 *
	 * @since 3.2.0
	 * @var string
	 */
	public $relation;

	/**
	 * Database table to query for the metadata.
	 *
	 * @since 4.1.0
	 * @var string
	 */
	public $meta_table;

	/**
	 * Column in meta_table that represents the ID of the object the metadata belongs to.
	 *
	 * @since 4.1.0
	 * @var string
	 */
	public $meta_id_column;

	/**
	 * Database table that where the metadata's objects are stored (eg $wpdb->users).
	 *
	 * @since 4.1.0
	 * @var string
	 */
	public $primary_table;

	/**
	 * Column in primary_table that represents the ID of the object.
	 *
	 * @since 4.1.0
	 * @var string
	 */
	public $primary_id_column;

	/**
	 * A flat list of table aliases used in JOIN clauses.
	 *
	 * @since 4.1.0
	 * @var array
	 */
	protected $table_aliases = array();

	/**
	 * A flat list of clauses, keyed by clause 'name'.
	 *
	 * @since 4.2.0
	 * @var array
	 */
	protected $clauses = array();

	/**
	 * Whether the query contains any OR relations.
	 *
	 * @since 4.3.0
	 * @var bool
	 */
	protected $has_or_relation = false;

	/**
	 * Constructor.
	 *
	 * @since 3.2.0
	 * @since 4.2.0 Introduced support for naming query clauses by associative array keys.
	 * @since 5.1.0 Introduced `$compare_key` clause parameter, which enables LIKE key matches.
	 * @since 5.3.0 Increased the number of operators available to `$compare_key`. Introduced `$type_key`,
	 *              which enables the `$key` to be cast to a new data type for comparisons.
	 *
	 * @param array $meta_query {
	 *     Array of meta query clauses. When first-order clauses or sub-clauses use strings as
	 *     their array keys, they may be referenced in the 'orderby' parameter of the parent query.
	 *
	 *     @type string $relation Optional. The MySQL keyword used to join the clauses of the query.
	 *                            Accepts 'AND' or 'OR'. Default 'AND'.
	 *     @type array  ...$0 {
	 *         Optional. An array of first-order clause parameters, or another fully-formed meta query.
	 *
	 *         @type string|string[] $key         Meta key or keys to filter by.
	 *         @type string          $compare_key MySQL operator used for comparing the $key. Accepts:
	 *                                            - '='
	 *                                            - '!='
	 *                                            - 'LIKE'
	 *                                            - 'NOT LIKE'
	 *                                            - 'IN'
	 *                                            - 'NOT IN'
	 *                                            - 'REGEXP'
	 *                                            - 'NOT REGEXP'
	 *                                            - 'RLIKE'
	 *                                            - 'EXISTS' (alias of '=')
	 *                                            - 'NOT EXISTS' (alias of '!=')
	 *                                            Default is 'IN' when `$key` is an array, '=' otherwise.
	 *         @type string          $type_key    MySQL data type that the meta_key column will be CAST to for
	 *                                            comparisons. Accepts 'BINARY' for case-sensitive regular expression
	 *                                            comparisons. Default is ''.
	 *         @type string|string[] $value       Meta value or values to filter by.
	 *         @type string          $compare     MySQL operator used for comparing the $value. Accepts:
	 *                                            - '='
	 *                                            - '!='
	 *                                            - '>'
	 *                                            - '>='
	 *                                            - '<'
	 *                                            - '<='
	 *                                            - 'LIKE'
	 *                                            - 'NOT LIKE'
	 *                                            - 'IN'
	 *                                            - 'NOT IN'
	 *                                            - 'BETWEEN'
	 *                                            - 'NOT BETWEEN'
	 *                                            - 'REGEXP'
	 *                                            - 'NOT REGEXP'
	 *                                            - 'RLIKE'
	 *                                            - 'EXISTS'
	 *                                            - 'NOT EXISTS'
	 *                                            Default is 'IN' when `$value` is an array, '=' otherwise.
	 *         @type string          $type        MySQL data type that the meta_value column will be CAST to for
	 *                                            comparisons. Accepts:
	 *                                            - 'NUMERIC'
	 *                                            - 'BINARY'
	 *                                            - 'CHAR'
	 *                                            - 'DATE'
	 *                                            - 'DATETIME'
	 *                                            - 'DECIMAL'
	 *                                            - 'SIGNED'
	 *                                            - 'TIME'
	 *                                            - 'UNSIGNED'
	 *                                            Default is 'CHAR'.
	 *     }
	 * }
	 */
	public function __construct( $meta_query = false ) {
		if ( ! $meta_query ) {
			return;
		}

		if ( isset( $meta_query['relation'] ) && 'OR' === strtoupper( $meta_query['relation'] ) ) {
			$this->relation = 'OR';
		} else {
			$this->relation = 'AND';
		}

		$this->queries = $this->sanitize_query( $meta_query );
	}

	/**
	 * Ensures the 'meta_query' argument passed to the class constructor is well-formed.
	 *
	 * Eliminates empty items and ensures that a 'relation' is set.
	 *
	 * @since 4.1.0
	 *
	 * @param array $queries Array of query clauses.
	 * @return array Sanitized array of query clauses.
	 */
	public function sanitize_query( $queries ) {
		$clean_queries = array();

		if ( ! is_array( $queries ) ) {
			return $clean_queries;
		}

		foreach ( $queries as $key => $query ) {
			if ( 'relation' === $key ) {
				$relation = $query;

			} elseif ( ! is_array( $query ) ) {
				continue;

				// First-order clause.
			} elseif ( $this->is_first_order_clause( $query ) ) {
				if ( isset( $query['value'] ) && array() === $query['value'] ) {
					unset( $query['value'] );
				}

				$clean_queries[ $key ] = $query;

				// Otherwise, it's a nested query, so we recurse.
			} else {
				$cleaned_query = $this->sanitize_query( $query );

				if ( ! empty( $cleaned_query ) ) {
					$clean_queries[ $key ] = $cleaned_query;
				}
			}
		}

		if ( empty( $clean_queries ) ) {
			return $clean_queries;
		}

		// Sanitize the 'relation' key provided in the query.
		if ( isset( $relation ) && 'OR' === strtoupper( $relation ) ) {
			$clean_queries['relation'] = 'OR';
			$this->has_or_relation     = true;

			/*
			* If there is only a single clause, call the relation 'OR'.
			* This value will not actually be used to join clauses, but it
			* simplifies the logic around combining key-only queries.
			*/
		} elseif ( 1 === count( $clean_queries ) ) {
			$clean_queries['relation'] = 'OR';

			// Default to AND.
		} else {
			$clean_queries['relation'] = 'AND';
		}

		return $clean_queries;
	}

	/**
	 * Determines whether a query clause is first-order.
	 *
	 * A first-order meta query clause is one that has either a 'key' or
	 * a 'value' array key.
	 *
	 * @since 4.1.0
	 *
	 * @param array $query Meta query arguments.
	 * @return bool Whether the query clause is a first-order clause.
	 */
	protected function is_first_order_clause( $query ) {
		return isset( $query['key'] ) || isset( $query['value'] );
	}

	/**
	 * Constructs a meta query based on 'meta_*' query vars
	 *
	 * @since 3.2.0
	 *
	 * @param array $qv The query variables.
	 */
	public function parse_query_vars( $qv ) {
		$meta_query = array();

		/*
		 * For orderby=meta_value to work correctly, simple query needs to be
		 * first (so that its table join is against an unaliased meta table) and
		 * needs to be its own clause (so it doesn't interfere with the logic of
		 * the rest of the meta_query).
		 */
		$primary_meta_query = array();
		foreach ( array( 'key', 'compare', 'type', 'compare_key', 'type_key' ) as $key ) {
			if ( ! empty( $qv[ "meta_$key" ] ) ) {
				$primary_meta_query[ $key ] = $qv[ "meta_$key" ];
			}
		}

		// WP_Query sets 'meta_value' = '' by default.
		if ( isset( $qv['meta_value'] ) && '' !== $qv['meta_value'] && ( ! is_array( $qv['meta_value'] ) || $qv['meta_value'] ) ) {
			$primary_meta_query['value'] = $qv['meta_value'];
		}

		$existing_meta_query = isset( $qv['meta_query'] ) && is_array( $qv['meta_query'] ) ? $qv['meta_query'] : array();

		if ( ! empty( $primary_meta_query ) && ! empty( $existing_meta_query ) ) {
			$meta_query = array(
				'relation' => 'AND',
				$primary_meta_query,
				$existing_meta_query,
			);
		} elseif ( ! empty( $primary_meta_query ) ) {
			$meta_query = array(
				$primary_meta_query,
			);
		} elseif ( ! empty( $existing_meta_query ) ) {
			$meta_query = $existing_meta_query;
		}

		$this->__construct( $meta_query );
	}

	/**
	 * Returns the appropriate alias for the given meta type if applicable.
	 *
	 * @since 3.7.0
	 *
	 * @param string $type MySQL type to cast meta_value.
	 * @return string MySQL type.
	 */
	public function get_cast_for_type( $type = '' ) {
		if ( empty( $type ) ) {
			return 'CHAR';
		}

		$meta_type = strtoupper( $type );

		if ( ! preg_match( '/^(?:BINARY|CHAR|DATE|DATETIME|SIGNED|UNSIGNED|TIME|NUMERIC(?:\(\d+(?:,\s?\d+)?\))?|DECIMAL(?:\(\d+(?:,\s?\d+)?\))?)$/', $meta_type ) ) {
			return 'CHAR';
		}

		if ( 'NUMERIC' === $meta_type ) {
			$meta_type = 'SIGNED';
		}

		return $meta_type;
	}

	/**
	 * Generates SQL clauses to be appended to a main query.
	 *
	 * @since 3.2.0
	 *
	 * @param string $type              Type of meta. Possible values include but are not limited
	 *                                  to 'post', 'comment', 'blog', 'term', and 'user'.
	 * @param string $primary_table     Database table where the object being filtered is stored (eg wp_users).
	 * @param string $primary_id_column ID column for the filtered object in $primary_table.
	 * @param object $context           Optional. The main query object that corresponds to the type, for
	 *                                  example a `WP_Query`, `WP_User_Query`, or `WP_Site_Query`.
	 *                                  Default null.
	 * @return string[]|false {
	 *     Array containing JOIN and WHERE SQL clauses to append to the main query,
	 *     or false if no table exists for the requested meta type.
	 *
	 *     @type string $join  SQL fragment to append to the main JOIN clause.
	 *     @type string $where SQL fragment to append to the main WHERE clause.
	 * }
	 */
	public function get_sql( $type, $primary_table, $primary_id_column, $context = null ) {
		$meta_table = _get_meta_table( $type );
		if ( ! $meta_table ) {
			return false;
		}

		$this->table_aliases = array();

		$this->meta_table     = $meta_table;
		$this->meta_id_column = sanitize_key( $type . '_id' );

		$this->primary_table     = $primary_table;
		$this->primary_id_column = $primary_id_column;

		$sql = $this->get_sql_clauses();

		/*
		 * If any JOINs are LEFT JOINs (as in the case of NOT EXISTS), then all JOINs should
		 * be LEFT. Otherwise posts with no metadata will be excluded from results.
		 */
		if ( str_contains( $sql['join'], 'LEFT JOIN' ) ) {
			$sql['join'] = str_replace( 'INNER JOIN', 'LEFT JOIN', $sql['join'] );
		}

		/**
		 * Filters the meta query's generated SQL.
		 *
		 * @since 3.1.0
		 *
		 * @param string[] $sql               Array containing the query's JOIN and WHERE clauses.
		 * @param array    $queries           Array of meta queries.
		 * @param string   $type              Type of meta. Possible values include but are not limited
		 *                                    to 'post', 'comment', 'blog', 'term', and 'user'.
		 * @param string   $primary_table     Primary table.
		 * @param string   $primary_id_column Primary column ID.
		 * @param object   $context           The main query object that corresponds to the type, for
		 *                                    example a `WP_Query`, `WP_User_Query`, or `WP_Site_Query`.
		 */
		return apply_filters_ref_array( 'get_meta_sql', array( $sql, $this->queries, $type, $primary_table, $primary_id_column, $context ) );
	}

	/**
	 * Generates SQL clauses to be appended to a main query.
	 *
	 * Called by the public WP_Meta_Query::get_sql(), this method is abstracted
	 * out to maintain parity with the other Query classes.
	 *
	 * @since 4.1.0
	 *
	 * @return string[] {
	 *     Array containing JOIN and WHERE SQL clauses to append to the main query.
	 *
	 *     @type string $join  SQL fragment to append to the main JOIN clause.
	 *     @type string $where SQL fragment to append to the main WHERE clause.
	 * }
	 */
	protected function get_sql_clauses() {
		/*
		 * $queries are passed by reference to get_sql_for_query() for recursion.
		 * To keep $this->queries unaltered, pass a copy.
		 */
		$queries = $this->queries;
		$sql     = $this->get_sql_for_query( $queries );

		if ( ! empty( $sql['where'] ) ) {
			$sql['where'] = ' AND ' . $sql['where'];
		}

		return $sql;
	}

	/**
	 * Generates SQL clauses for a single query array.
	 *
	 * If nested subqueries are found, this method recurses the tree to
	 * produce the properly nested SQL.
	 *
	 * @since 4.1.0
	 *
	 * @param array $query Query to parse (passed by reference).
	 * @param int   $depth Optional. Number of tree levels deep we currently are.
	 *                     Used to calculate indentation. Default 0.
	 * @return string[] {
	 *     Array containing JOIN and WHERE SQL clauses to append to a single query array.
	 *
	 *     @type string $join  SQL fragment to append to the main JOIN clause.
	 *     @type string $where SQL fragment to append to the main WHERE clause.
	 * }
	 */
	protected function get_sql_for_query( &$query, $depth = 0 ) {
		$sql_chunks = array(
			'join'  => array(),
			'where' => array(),
		);

		$sql = array(
			'join'  => '',
			'where' => '',
		);

		$indent = '';
		for ( $i = 0; $i < $depth; $i++ ) {
			$indent .= '  ';
		}

		foreach ( $query as $key => &$clause ) {
			if ( 'relation' === $key ) {
				$relation = $query['relation'];
			} elseif ( is_array( $clause ) ) {

				// This is a first-order clause.
				if ( $this->is_first_order_clause( $clause ) ) {
					$clause_sql = $this->get_sql_for_clause( $clause, $query, $key );

					$where_count = count( $clause_sql['where'] );
					if ( ! $where_count ) {
						$sql_chunks['where'][] = '';
					} elseif ( 1 === $where_count ) {
						$sql_chunks['where'][] = $clause_sql['where'][0];
					} else {
						$sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
					}

					$sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
					// This is a subquery, so we recurse.
				} else {
					$clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );

					$sql_chunks['where'][] = $clause_sql['where'];
					$sql_chunks['join'][]  = $clause_sql['join'];
				}
			}
		}

		// Filter to remove empties.
		$sql_chunks['join']  = array_filter( $sql_chunks['join'] );
		$sql_chunks['where'] = array_filter( $sql_chunks['where'] );

		if ( empty( $relation ) ) {
			$relation = 'AND';
		}

		// Filter duplicate JOIN clauses and combine into a single string.
		if ( ! empty( $sql_chunks['join'] ) ) {
			$sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
		}

		// Generate a single WHERE clause with proper brackets and indentation.
		if ( ! empty( $sql_chunks['where'] ) ) {
			$sql['where'] = '( ' . "\n  " . $indent . implode( ' ' . "\n  " . $indent . $relation . ' ' . "\n  " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
		}

		return $sql;
	}

	/**
	 * Generates SQL JOIN and WHERE clauses for a first-order query clause.
	 *
	 * "First-order" means that it's an array with a 'key' or 'value'.
	 *
	 * @since 4.1.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param array  $clause       Query clause (passed by reference).
	 * @param array  $parent_query Parent query array.
	 * @param string $clause_key   Optional. The array key used to name the clause in the original `$meta_query`
	 *                             parameters. If not provided, a key will be generated automatically.
	 *                             Default empty string.
	 * @return array {
	 *     Array containing JOIN and WHERE SQL clauses to append to a first-order query.
	 *
	 *     @type string[] $join  Array of SQL fragments to append to the main JOIN clause.
	 *     @type string[] $where Array of SQL fragments to append to the main WHERE clause.
	 * }
	 */
	public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) {
		global $wpdb;

		$sql_chunks = array(
			'where' => array(),
			'join'  => array(),
		);

		if ( isset( $clause['compare'] ) ) {
			$clause['compare'] = strtoupper( $clause['compare'] );
		} else {
			$clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
		}

		$non_numeric_operators = array(
			'=',
			'!=',
			'LIKE',
			'NOT LIKE',
			'IN',
			'NOT IN',
			'EXISTS',
			'NOT EXISTS',
			'RLIKE',
			'REGEXP',
			'NOT REGEXP',
		);

		$numeric_operators = array(
			'>',
			'>=',
			'<',
			'<=',
			'BETWEEN',
			'NOT BETWEEN',
		);

		if ( ! in_array( $clause['compare'], $non_numeric_operators, true ) && ! in_array( $clause['compare'], $numeric_operators, true ) ) {
			$clause['compare'] = '=';
		}

		if ( isset( $clause['compare_key'] ) ) {
			$clause['compare_key'] = strtoupper( $clause['compare_key'] );
		} else {
			$clause['compare_key'] = isset( $clause['key'] ) && is_array( $clause['key'] ) ? 'IN' : '=';
		}

		if ( ! in_array( $clause['compare_key'], $non_numeric_operators, true ) ) {
			$clause['compare_key'] = '=';
		}

		$meta_compare     = $clause['compare'];
		$meta_compare_key = $clause['compare_key'];

		// First build the JOIN clause, if one is required.
		$join = '';

		// We prefer to avoid joins if possible. Look for an existing join compatible with this clause.
		$alias = $this->find_compatible_table_alias( $clause, $parent_query );
		if ( false === $alias ) {
			$i     = count( $this->table_aliases );
			$alias = $i ? 'mt' . $i : $this->meta_table;

			// JOIN clauses for NOT EXISTS have their own syntax.
			if ( 'NOT EXISTS' === $meta_compare ) {
				$join .= " LEFT JOIN $this->meta_table";
				$join .= $i ? " AS $alias" : '';

				if ( 'LIKE' === $meta_compare_key ) {
					$join .= $wpdb->prepare( " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key LIKE %s )", '%' . $wpdb->esc_like( $clause['key'] ) . '%' );
				} else {
					$join .= $wpdb->prepare( " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
				}

				// All other JOIN clauses.
			} else {
				$join .= " INNER JOIN $this->meta_table";
				$join .= $i ? " AS $alias" : '';
				$join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
			}

			$this->table_aliases[] = $alias;
			$sql_chunks['join'][]  = $join;
		}

		// Save the alias to this clause, for future siblings to find.
		$clause['alias'] = $alias;

		// Determine the data type.
		$_meta_type     = isset( $clause['type'] ) ? $clause['type'] : '';
		$meta_type      = $this->get_cast_for_type( $_meta_type );
		$clause['cast'] = $meta_type;

		// Fallback for clause keys is the table alias. Key must be a string.
		if ( is_int( $clause_key ) || ! $clause_key ) {
			$clause_key = $clause['alias'];
		}

		// Ensure unique clause keys, so none are overwritten.
		$iterator        = 1;
		$clause_key_base = $clause_key;
		while ( isset( $this->clauses[ $clause_key ] ) ) {
			$clause_key = $clause_key_base . '-' . $iterator;
			++$iterator;
		}

		// Store the clause in our flat array.
		$this->clauses[ $clause_key ] =& $clause;

		// Next, build the WHERE clause.

		// meta_key.
		if ( array_key_exists( 'key', $clause ) ) {
			if ( 'NOT EXISTS' === $meta_compare ) {
				$sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
			} else {
				/**
				 * In joined clauses negative operators have to be nested into a
				 * NOT EXISTS clause and flipped, to avoid returning records with
				 * matching post IDs but different meta keys. Here we prepare the
				 * nested clause.
				 */
				if ( in_array( $meta_compare_key, array( '!=', 'NOT IN', 'NOT LIKE', 'NOT EXISTS', 'NOT REGEXP' ), true ) ) {
					// Negative clauses may be reused.
					$i                     = count( $this->table_aliases );
					$subquery_alias        = $i ? 'mt' . $i : $this->meta_table;
					$this->table_aliases[] = $subquery_alias;

					$meta_compare_string_start  = 'NOT EXISTS (';
					$meta_compare_string_start .= "SELECT 1 FROM $wpdb->postmeta $subquery_alias ";
					$meta_compare_string_start .= "WHERE $subquery_alias.post_ID = $alias.post_ID ";
					$meta_compare_string_end    = 'LIMIT 1';
					$meta_compare_string_end   .= ')';
				}

				switch ( $meta_compare_key ) {
					case '=':
					case 'EXISTS':
						$where = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
						break;
					case 'LIKE':
						$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
						$where              = $wpdb->prepare( "$alias.meta_key LIKE %s", $meta_compare_value ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
						break;
					case 'IN':
						$meta_compare_string = "$alias.meta_key IN (" . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ')';
						$where               = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
						break;
					case 'RLIKE':
					case 'REGEXP':
						$operator = $meta_compare_key;
						if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) {
							$cast     = 'BINARY';
							$meta_key = "CAST($alias.meta_key AS BINARY)";
						} else {
							$cast     = '';
							$meta_key = "$alias.meta_key";
						}
						$where = $wpdb->prepare( "$meta_key $operator $cast %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
						break;

					case '!=':
					case 'NOT EXISTS':
						$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key = %s " . $meta_compare_string_end;
						$where               = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
						break;
					case 'NOT LIKE':
						$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key LIKE %s " . $meta_compare_string_end;

						$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
						$where              = $wpdb->prepare( $meta_compare_string, $meta_compare_value ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
						break;
					case 'NOT IN':
						$array_subclause     = '(' . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ') ';
						$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key IN " . $array_subclause . $meta_compare_string_end;
						$where               = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
						break;
					case 'NOT REGEXP':
						$operator = $meta_compare_key;
						if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) {
							$cast     = 'BINARY';
							$meta_key = "CAST($subquery_alias.meta_key AS BINARY)";
						} else {
							$cast     = '';
							$meta_key = "$subquery_alias.meta_key";
						}

						$meta_compare_string = $meta_compare_string_start . "AND $meta_key REGEXP $cast %s " . $meta_compare_string_end;
						$where               = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
						break;
				}

				$sql_chunks['where'][] = $where;
			}
		}

		// meta_value.
		if ( array_key_exists( 'value', $clause ) ) {
			$meta_value = $clause['value'];

			if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ), true ) ) {
				if ( ! is_array( $meta_value ) ) {
					$meta_value = preg_split( '/[,\s]+/', $meta_value );
				}
			} elseif ( is_string( $meta_value ) ) {
				$meta_value = trim( $meta_value );
			}

			switch ( $meta_compare ) {
				case 'IN':
				case 'NOT IN':
					$meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
					$where               = $wpdb->prepare( $meta_compare_string, $meta_value );
					break;

				case 'BETWEEN':
				case 'NOT BETWEEN':
					$where = $wpdb->prepare( '%s AND %s', $meta_value[0], $meta_value[1] );
					break;

				case 'LIKE':
				case 'NOT LIKE':
					$meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
					$where      = $wpdb->prepare( '%s', $meta_value );
					break;

				// EXISTS with a value is interpreted as '='.
				case 'EXISTS':
					$meta_compare = '=';
					$where        = $wpdb->prepare( '%s', $meta_value );
					break;

				// 'value' is ignored for NOT EXISTS.
				case 'NOT EXISTS':
					$where = '';
					break;

				default:
					$where = $wpdb->prepare( '%s', $meta_value );
					break;

			}

			if ( $where ) {
				if ( 'CHAR' === $meta_type ) {
					$sql_chunks['where'][] = "$alias.meta_value {$meta_compare} {$where}";
				} else {
					$sql_chunks['where'][] = "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$where}";
				}
			}
		}

		/*
		 * Multiple WHERE clauses (for meta_key and meta_value) should
		 * be joined in parentheses.
		 */
		if ( 1 < count( $sql_chunks['where'] ) ) {
			$sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
		}

		return $sql_chunks;
	}

	/**
	 * Gets a flattened list of sanitized meta clauses.
	 *
	 * This array should be used for clause lookup, as when the table alias and CAST type must be determined for
	 * a value of 'orderby' corresponding to a meta clause.
	 *
	 * @since 4.2.0
	 *
	 * @return array Meta clauses.
	 */
	public function get_clauses() {
		return $this->clauses;
	}

	/**
	 * Identifies an existing table alias that is compatible with the current
	 * query clause.
	 *
	 * We avoid unnecessary table joins by allowing each clause to look for
	 * an existing table alias that is compatible with the query that it
	 * needs to perform.
	 *
	 * An existing alias is compatible if (a) it is a sibling of `$clause`
	 * (ie, it's under the scope of the same relation), and (b) the combination
	 * of operator and relation between the clauses allows for a shared table join.
	 * In the case of WP_Meta_Query, this only applies to 'IN' clauses that are
	 * connected by the relation 'OR'.
	 *
	 * @since 4.1.0
	 *
	 * @param array $clause       Query clause.
	 * @param array $parent_query Parent query of $clause.
	 * @return string|false Table alias if found, otherwise false.
	 */
	protected function find_compatible_table_alias( $clause, $parent_query ) {
		$alias = false;

		foreach ( $parent_query as $sibling ) {
			// If the sibling has no alias yet, there's nothing to check.
			if ( empty( $sibling['alias'] ) ) {
				continue;
			}

			// We're only interested in siblings that are first-order clauses.
			if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
				continue;
			}

			$compatible_compares = array();

			// Clauses connected by OR can share joins as long as they have "positive" operators.
			if ( 'OR' === $parent_query['relation'] ) {
				$compatible_compares = array( '=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=' );

				// Clauses joined by AND with "negative" operators share a join only if they also share a key.
			} elseif ( isset( $sibling['key'] ) && isset( $clause['key'] ) && $sibling['key'] === $clause['key'] ) {
				$compatible_compares = array( '!=', 'NOT IN', 'NOT LIKE' );
			}

			$clause_compare  = strtoupper( $clause['compare'] );
			$sibling_compare = strtoupper( $sibling['compare'] );
			if ( in_array( $clause_compare, $compatible_compares, true ) && in_array( $sibling_compare, $compatible_compares, true ) ) {
				$alias = preg_replace( '/\W/', '_', $sibling['alias'] );
				break;
			}
		}

		/**
		 * Filters the table alias identified as compatible with the current clause.
		 *
		 * @since 4.1.0
		 *
		 * @param string|false  $alias        Table alias, or false if none was found.
		 * @param array         $clause       First-order query clause.
		 * @param array         $parent_query Parent of $clause.
		 * @param WP_Meta_Query $query        WP_Meta_Query object.
		 */
		return apply_filters( 'meta_query_find_compatible_table_alias', $alias, $clause, $parent_query, $this );
	}

	/**
	 * Checks whether the current query has any OR relations.
	 *
	 * In some cases, the presence of an OR relation somewhere in the query will require
	 * the use of a `DISTINCT` or `GROUP BY` keyword in the `SELECT` clause. The current
	 * method can be used in these cases to determine whether such a clause is necessary.
	 *
	 * @since 4.3.0
	 *
	 * @return bool True if the query contains any `OR` relations, otherwise false.
	 */
	public function has_or_relation() {
		return $this->has_or_relation;
	}
}
Is Bizzo Casino the Ultimate Online Gaming Experience_21

Is Bizzo Casino the Ultimate Online Gaming Experience_21

Is Bizzo Casino the Ultimate Online Gaming Experience?

Online gaming has witnessed an exponential rise in popularity over the past decade, with countless platforms vying for the attention of enthusiastic players. Among these platforms, Bizzo Casino has emerged as a formidable contender, promising a unique blend of exciting games, enticing bonuses, and an overall engaging user experience. As prospective players consider which platform to trust for their gaming experience, assessing each option’s offerings becomes crucial in making an informed decision.

Bizzo Casino sets itself apart by establishing a comprehensive set of features tailored to meet both casual players and seasoned gamers’ needs. With thousands of games spanning various genres, an intuitive interface, and dedicated customer support, players are treated to a holistic gaming environment. But does it truly live up to the hype? This article delves deeper into the various aspects of Bizzo Casino, evaluating everything from game variety and software developers to payment options and user experience.

As we explore the captivating world of Bizzo Casino, it becomes essential to dissect all the vital elements that combine to create its reputation. Factors such as licensing, security measures, and mobile compatibility also play a significant role in shaping user perceptions and experiences. Above all, we will determine if Bizzo Casino indeed stands out as the ultimate online gaming destination amidst the growing competition.

In the following sections, we will explore the platform’s extensive game library, bonuses, promotions, and other critical features that contribute to an enjoyable gaming experience. Each segment will offer insights into how Bizzo Casino manages to cater to its audience effectively, assisting players in making the best choices for their gaming endeavors.

Ultimately, the goal is to evaluate whether Bizzo Casino lives up to expectations and solidifies itself as a premier choice for enthusiasts seeking entertainment and rewards in the online gaming landscape. Let’s dive into the details and see what makes Bizzo Casino a noteworthy destination for players everywhere.

Understanding Bizzo Casino’s Game Library

One of the most enticing aspects of any online casino is its game library, and Bizzo Casino certainly does not disappoint. With hundreds of games available, players are greeted with an impressive array of options. From classic table games such as blackjack and poker to exciting slot machines boasting stunning graphics and immersive storylines, the variety is astonishing.

In order to provide players with the best possible experience, Bizzo Casino collaborates with some of the most reputable software developers in the industry. This ensures that the games are not only high-quality but also fair and secure. Players can find popular titles from renowned providers such as Microgaming, NetEnt, and Evolution Gaming, among others.

Game Type
Popular Titles
Slots Starburst, Book of Dead
Table Games Blackjack, Roulette
Live Casino Live Blackjack, Live Roulette

Another crucial aspect of Bizzo Casino’s offerings is the inclusion of live dealer games, which provide players with an immersive gambling experience. Engaging with professional dealers in real-time adds a sense of authenticity that many players find appealing. These live games are designed to recreate the thrill of a traditional casino while maintaining the convenience of online play.

Variety of Slots and Table Games

Slots are undoubtedly one of the main attractions at Bizzo Casino. With an extensive collection that includes hundreds of titles, players can always find something that piques their interest. Slots can vary widely in themes, features, and potential payouts, making them attractive to a diverse audience. The incorporation of progressive jackpots also offers opportunities for substantial winnings, setting the stage for thrilling gaming experiences.

In addition to slots, Bizzo Casino boasts a range of classic table games. Players can indulge in favorites like poker, blackjack, and baccarat, each coming with various versions to cater to different preferences. New players can easily grasp the basic rules while seasoned gamers can delve into more complex variations to enhance their overall experience.

Live Casino Experience

The live casino segment of Bizzo Casino is one area where the platform truly shines. With state-of-the-art technology, players can engage in real-time gameplay with professional dealers. This adds an interactive element, allowing players to communicate and experience the atmosphere of a physical casino from the comfort of their homes.

The live games offered cover various categories, including traditional card games and modern variations appealing to younger audiences. By utilizing high-definition streaming and user-friendly interfaces, Bizzo Casino ensures a smooth experience for players looking to enjoy live dealer gaming.

Bonuses and Promotions Offered by Bizzo Casino

When it comes to attracting and retaining players, generous bonuses and promotions are key strategies for online casinos. Bizzo Casino excels in this aspect by offering an enticing selection of incentives to both new and existing players. These bonuses can significantly enhance the gaming experience and provide extra chances to win.

New players are often greeted with a welcome bonus that typically includes a deposit match and free spins. This promotional strategy encourages players to start exploring the game library and testing their luck. However, it’s essential for players to read the terms and conditions associated with these offers to maximize their benefits.

  • Welcome Bonus: A generous sign-up bonus for new players.
  • Free Spins: Additional spins to try selected slot games.
  • Weekly Promotions: Ongoing offers for regular players.
  • Loyalty Rewards: Rewards program for frequent players.

Additionally, Bizzo Casino features regular promotions and loyalty rewards programs designed to create a sense of community among its players. These initiatives encourage players to engage with the platform consistently, making it a go-to choice for online gaming.

Understanding Wagering Requirements

While bonuses can be enticing, it is important for players to familiarize themselves with wagering requirements. These requirements often dictate how many times a player needs to wager their bonus before being eligible to withdraw any winnings. It’s advisable to read the fine print to avoid surprises later on.

Bizzo Casino generally strives to maintain reasonable wagering requirements, but players should double-check current promotions, as they may vary. Staying informed will help players navigate their bonus options more effectively.

Exclusive VIP Programs

The VIP experience at Bizzo Casino is yet another incentive that attracts players to remain loyal. VIP members can enjoy exclusive perks, including personalized account managers, special bonuses, and faster withdrawals. These benefits are designed to create a more tailored gaming experience for committed players, ensuring they are valued for their loyalty.

By incentivizing players to rise through the ranks of the loyalty program, Bizzo Casino fosters a sense of belonging and appreciation. This ultimately enhances player satisfaction, leading to a more invested community.

Payment Methods and Security Standards

For any online casino, offering a wide range of secure payment methods is vital for attracting and retaining players. Bizzo Casino recognizes this need and provides numerous options for deposits and withdrawals, catering to various preferences and geographical locations. Players can choose from traditional bank transfers, credit cards, and popular e-wallets, ensuring that their transactions are seamless.

Security also plays a critical role in establishing trust. Bizzo Casino utilizes advanced encryption technology to protect players’ personal and financial data. This commitment to maintaining high security standards contributes to a safer gaming environment, allowing players to focus on enjoying their gaming experience without anxiety about their information being compromised.

Payment Method
Type
Visa Credit/Debit Card
PayPal E-Wallet
Bitcoin Cryptocurrency

To ensure a smooth deposit experience, players should take advantage of the various payment options available. Additionally, understanding withdrawal processing times and any associated fees is crucial for a satisfactory gaming experience. Bizzo Casino’s efforts to maintain transparency in its payment processes help build a relationship of trust with its players.

Deposits and Withdrawals

Players can deposit funds into their Bizzo Casino accounts through several convenient methods. The process is typically fast and hassle-free, allowing players to begin gaming without unnecessary delays. Once players are ready to withdraw their winnings, understanding the processing time associated with different methods is important. Some options may take longer than others, so being aware of this will help set expectations for players.

In most cases, e-wallets facilitate quicker withdrawals, making them the preferred option for many players. However, traditional bank methods may require longer processing times before winnings appear in players’ accounts.

Safety Protocols in Place

Bizzo Casino’s commitment to player security is evident through its safety protocols. Using SSL encryption, the platform safeguards sensitive information, ensuring that players can enjoy their gaming experience without fear of data breaches. Additionally, the casino is licensed and regulated by recognized authorities, further bolstering its credibility.

By implementing robust security measures, Bizzo Casino enhances player confidence, enabling them to focus on the fun rather than concerns about safety. This aspect is essential in a rapidly evolving gaming landscape, where security breaches remain a pressing issue.

User Experience and Interface

The user experience at Bizzo Casino is crafted with player needs in mind. The website features an intuitive interface that allows players to navigate effortlessly through various sections. Whether they are searching for specific games or exploring promotions, the layout is designed to facilitate a pleasant user experience.

Mobile compatibility is another critical aspect of the user experience. With an increasing number of players opting for mobile gaming, Bizzo Casino ensures that its platform is fully optimized for smartphones and tablets. This adaptation allows for seamless gaming on the go, catering to players’ busy lifestyles while still delivering high-quality gameplay.

  • Responsive Design: Mobile-friendly interface for seamless gaming.
  • Intuitive Navigation: Easy access to games and promotions.
  • Customer Support: Available via multiple channels for player convenience.
  • Quick Loading Times: Optimized performance for a smooth gaming experience.

Furthermore, Bizzo Casino offers multiple customer support options, including live chat, email, and an extensive FAQ section. This dedication to providing assistance ensures that players can receive help when needed, enhancing their overall experience.

Customer Support Availability

Having effective customer support available is crucial for online gaming platforms. Bizzo Casino recognizes this importance and gives players access to a supportive team ready to address any inquiries or concerns. The live chat feature stands out as the quickest way to receive assistance.

The FAQ section is also a valuable resource, offering detailed answers to common questions. By providing comprehensive support options, Bizzo Casino demonstrates its commitment to player satisfaction and experience, effectively building loyalty among its users.

Loading Speed and Performance

In today’s fast-paced world, players expect online platforms to deliver rapidly. Bizzo Casino understands the importance of performance and ensures that the website loads quickly, providing seamless gameplay. Whether on a PC or a mobile device, players can enjoy their favorite games without frustrating delays.

The focus on performance translates directly into player satisfaction, as gamers can enjoy uninterrupted fun. Regular updates and optimization are part of Bizzo Casino’s strategy to deliver an exceptional overall experience to its users.

The Mobile Gaming Advantage

The mobile gaming experience has dramatically transformed the industry, making it essential for casinos to adapt. Bizzo Casino has embraced this trend, optimizing their platform for mobile devices. Players can access a wide range of games, bonuses, and features while on the go, demonstrating the casino’s commitment to catering to contemporary gamers.

Mobile gaming offers numerous advantages, including convenience and flexibility. Players can engage in their favorite casino activities anytime and anywhere, enhancing their overall gaming experience. This accessibility is particularly appealing to those with busy schedules or who prefer gaming while traveling.

  1. Convenience: Play anywhere at any time with mobile access.
  2. Broad Game Variety: Access numerous games optimized for mobile play.
  3. Instant Updates: Receive the latest promotions and game releases on mobile.

Moreover, the mobile version of Bizzo Casino retains all the features of the desktop platform, ensuring players receive a consistent experience regardless of the device. In addition, mobile players often receive special promotions, attracting even more users to play on their smartphones.

Features of the Mobile Site

The mobile site is designed to provide a seamless experience with a user-friendly interface that displays well on various screen sizes. Navigating through games and promotions is quick and simple, making it easy for players to find their favorites. The mobile platform also maintains the same level of security as the desktop version, ensuring confidential information remains well-protected.

Furthermore, as mobile gaming continues to expand, Bizzo Casino remains proactive in enhancing its mobile offerings, regularly implementing updates and improvements to cater to evolving player preferences.

The Future of Mobile Gaming at Bizzo Casino

As mobile technology continues to advance, Bizzo Casino will likely adopt new innovations to improve their gaming experience further. Staying abreast of industry trends, the casino aims to remain competitive in a crowded marketplace. By incorporating new technologies and features, Bizzo Casino can create unique gaming opportunities for both new and existing players.

Ultimately, the future of mobile gaming at Bizzo Casino looks promising, positioning the platform as a leader in the ever-evolving landscape of online gaming.

Conclusion

In conclusion, Bizzo Casino presents a well-rounded online gaming experience that caters to various player preferences. With an extensive game library, generous bonuses, and a commitment to security and customer support, it stands out as a formidable player in the online gaming landscape. While no platform is without its challenges, Bizzo Casino appears well-equipped to meet the demands of modern players.

As gaming technology continues to evolve, staying attuned to player needs will be crucial for maintaining and enhancing the overall experience. If you are considering an online casino that offers a broad selection of games, engaging promotions, and a secure environment, Bizzo Casino may very well be the ultimate destination for your online gaming adventures.

Check Also

Améliorez vos gains avec des stratégies innovantes et attrayantes.

Améliorez vos gains avec des stratégies innovantes et attrayantes. Comprendre le terrain de jeu Recherchez …