????

Your IP : 3.144.255.247


Current Path : /home/r6536736/public_html/tactics-roof.com/wp-includes/
Upload File :
Current File : /home/r6536736/public_html/tactics-roof.com/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;
	}
}

京都の外壁塗装で選ぶべき評判・口コミの良い業者ランキング【2021年】

京都の外壁塗装で選ぶべき評判・口コミの良い業者ランキング【2021年】

京都の外壁塗装業者ランキング
京都の外壁塗装業者を評判・口コミから厳選

京都の外壁塗装業者を徹底調査!

京都で評判の良いおすすめ外壁塗装業者ランキング!

京都で評判・口コミの良い外壁塗装業者ランキング!

こんにちは、「京都のおすすめ外壁塗装業者を実績・評判から厳選して10社ご紹介」の管理人です。
この度は当サイトをご覧いただきき、本当にありがとうございます。

このサイトでは、京都で生まれ育った管理人である私が、地元である京都の優良外壁塗装業者をご紹介しています。
京都にお住まいの方で、外壁塗装を検討されている方にとって少しでもお役に立てれば幸いです。

まず、なぜ私が「京都の優良外壁塗装業者」を紹介しようと思ったのか? 手短にご説明させていただきます。

実は最近、たくさんの思い出が詰まった我が家の外壁塗装工事を行いました。

築年数は約20年程。 築20年を超えたくらいのタイミングで塗り替えをしないと家の寿命が短くなってしまうと聞いたこと。
そして何より、この20年一切外壁には手をかけていなかったので、汚れが目立ち美観がすごく悪くなっていたこと。
これが初めて外壁塗装の塗り替えを検討するきっかけとなりました。

私は性格的に凝り性で、何でも自分で調べないと気が済まない性格です。
自分が納得するまで徹底的に調査して、どこよりも良い塗装業者さんを見つけて塗り替えをしてもらおう!と意気込みました。

幸いにも、私は職業柄、そして長年京都に住み続けていることもあり、建築関係(大工さん・建築士さん・設計士さんなど)の知人が複数います。
実際に行った調査方法として、その建築関係の知人と直接会い、徹底的に塗装業界を含む建築業界の生の声を聞き込みました。

その結果、納得・安心して塗り替えをお願いできる塗装業者さんと出会うことができ、仕上がり・工事金額ともに満足のいく塗り替えをすることができました。

私と同じように、

・大切な家だからこそ、丁寧にしっかりと外壁塗装をしてほしい
・少しでも安くなれば嬉しいけど、手抜き工事はされたくない
・しっかり工事内容を説明してくれるような、信頼できる塗装業者を見つけたい

とお考えの方は、きっとこのサイトが京都での塗装業者探しの参考になると信じております。

ぜひ、京都にお住まいの方で、外壁塗装を検討されている方、優良塗装業者をお探しの方の参考にしてください。

京都で信頼できる外壁塗装業者を選ぶポイント

京都で信頼できる外壁塗装業者を選ぶポイント

今回、私が「優良外壁塗装業者の定義」として挙げたポイントは以下の3点です。

① 良心的な外壁塗装の金額設定
② 塗り替えの施工技術のレベルが高い
③ 対応品質・サポートがしっかりしている

恐らく皆さんにとっても、上記3点が揃っていれば優良塗装業者と言えるでしょう。
しかし、京都にも外壁塗装業者は数多くありますが、上記全てを満たす塗装業者というのは実は非常に少ないのです。

「値段が安くても、塗装工事自体の品質が悪い」
「仕上がりはすごく良いけど、工事金額が相場より明らかに高額」
「会社の規模は大きいが、施工は全て下請けに丸投げで対応が雑or下請け任せ」
など、どれか1つの項目は満たしても、他のポイントが良くないという塗装業者が圧倒的に多いのが現状です。

それでは、「優良外壁塗装業者の定義」をもう少し掘り下げてご説明します。

良心的な外壁塗装工事の金額設定

良心的な外壁塗装工事の金額設定

良心的な金額設定は、やはり皆さん重視したいポイントではないでしょうか?
私自身もここは絶対に外せないポイントでした。

一般的な戸建住宅の外壁塗装の価格相場は、おおよそ80万〜120万円とされています。
しかし、ただ安ければ良いという訳でない、施工品質が伴わないといけない、というのが難しいポイントです。

良心的な工事金額、その中で最大限高品質な塗り替えを行ってくれる塗装業者を見極めるポイント
それは、

営業マンやCM・チラシなど、過剰な営業費・宣伝広告費を使っていないかどうか、です。

外壁塗装業界は、大手メーカーから地元密着型の小さな塗装業者まで、お客さんの奪い合い状態となっています。
そのため、多くの塗装業者が他社より少しでも知名度を上げるため、少しでも多くのお客さんに知ってもらうために、多額の営業費・宣伝広告費を使っています。
大手メーカーであればCM、小さな塗装業者でも新聞チラシ、そして多くの営業マンを雇い、訪問販売による営業活動を行なっているのです。

もちろん塗装業者も生活がかかっているので、営業・宣伝を行い、少しでも仕事を受注しようとするのは当然です。
しかし問題は、多額の営業費・宣伝広告費は皆さんがお支払いになる工事代金に含まれる、という点です。

過剰な営業費・宣伝広告費を使っている塗装業者は、総じて塗り替えの工事金額が高額になりがちです。
こうなると、「なぜ私たちが工事には直接関係の無い営業費・宣伝広告費を支払わないといけないのか」と思ってしまいますよね。

本当に優良な塗装業者なら、広告を出したり営業マンを雇ったりしなくても評判・口コミでお客さんは自然と集まるのです。
ただでさえ価格相場の幅が広く、工事金額の内訳がわかりにくい外壁塗装です。
気になった塗装業者が、営業マンを雇っていないか、過剰な広告を出していないか、確認してみましょう。

塗り替えの施工技術のレベルが高い

塗り替えの施工技術のレベルが高い

施工技術・施工品質に関しては、気にはなりますがわかりにくいポイントです。
私もそうでしたが、普段塗装工事に馴染みが無い一般の方からすれば、実際に施工している姿を見ても、技術の良し悪しを見極めるのは難しいのです。

ここで1つの見極めポイントとなるのが、「一級塗装技能士」という資格です。

この「一級塗装技能士」は、塗装の実技試験と学科試験の両方に合格した塗装職人のみが持っている資格になります。
もちろんこれは国家資格です

資格を持っていない塗装職人さんでも、技術力が高い職人さんは沢山いらっしゃると思いますが、少なくともこの資格を持つ塗装職人さんは、一定水準以上の技術・知識を持つ塗装職人だと国から認められているのです。
気になった塗装業者に「一級塗装技能士」の取得者がいるのか、ぜひ確認しておきましょう。

塗装工事以外にも接客対応・サポートがしっかりしている

塗装工事以外にも対応・サポートがしっかりしている

外壁塗装を検討されている方の中で、外壁塗装について精通してるという方は少ないと思います。
なぜなら、外壁塗装の塗り替え周期は10~20年に一度、知らなくても当然なのです。
むしろ私のように、「初めて外壁塗装を検討している」という人の方が多いかもしれません。

一般の方が馴染みが薄い外壁塗装工事だからこそ、対応品質・サポートがしっかりしている塗装業者の方が安心して施工を任せられるでしょう。

打ち合わせや現地調査、見積もりの段階で、「わからないことはないか?心配な点はないか?」など、気遣ってくれる塗装業者は本当に心強いです。
初めて塗り替え工事を行う方なら、尚更安心して工事を任せることができます。
こちらの些細な疑問・質問にも、丁寧にしっかり対応してくれる塗装業者を選ぶようにしましょう。

また、不思議と対応品質が良い塗装業者は、総じて塗り替えの施工品質も高いです。
やはり、真面目に誠実に塗装と向き合っている業者は、その真面目さ・誠実さが対応品質にも現れるということですね。

京都で評判の良い外壁塗装業者はどこ?

京都で評判の良い外壁塗装業者はどこ?

以上のことを踏まえた上で私は、複数の塗装業者から見積もりをいただき、じっくりと見積書を比較検討し、塗装業者を吟味しました。
そしてその結果、京都の中でも大変素晴らしい外壁塗装業者さんと出会うことができ、仕上がり・価格ともに満足のいく外壁塗装工事をしていただくことができました。

ここでは、私が実際に塗り替えを依頼した塗装業者さんをはじめ、

・見積もりを依頼したり問い合わせたりした際に「3つの優良外壁塗装業者の定義を満たしている」と感じた塗装業者さん
・建築業界に在籍している知人の中で評判の良い塗装業者さん

この2点を含めた、京都で安心して塗装工事を任せることができる優良外壁塗装業者さんをランキング形式でご紹介させていただきます。

ぜひ京都にお住まいの方は、優良外壁塗装業者探しの参考にしてください。

京都で評判・口コミの良い外壁塗装業者ランキング
ランキング1位

京都で評判・口コミの良い外壁塗装業者ランキング

株式会社ウェルビーホーム

京都でおすすめの優良外壁塗装業者|株式会社ウェルビーホーム

株式会社ウェルビーホームさんの特徴

今回、私が実際に外壁塗装の塗り替えを依頼し、最も皆さんにもおすすめしたい外壁塗装業者さんは、「株式会社ウェルビーホーム」さんです。

ウェルビーホームさんは、代表の高橋さんが直接打ち合わせ・現場調査から実際の施工、そして工事後のアフターフォローまで全て対応してくれます。
また、高橋さんは建築士の資格も持っており、外壁塗装だけでなく住まいのこと全般に精通しておられるので、様々な観点から外壁塗装に関するアドバイスをしてくれます。
高橋さん自身とても笑顔の素敵な物腰の優しい方で、外壁塗装以外の住まいに関する質問にも、とてもわかりやすく丁寧に答えてくださいました。

見積書も、他のどの業者さんよりも丁寧で詳細に作ってくださり、工事内容が非常に明確で安心できたのがウェルビーホームさんを選んだ大きなポイントです。
さらに、ウェルビーホームさんは「一級塗装技能士」の資格を所持する職人さんが在籍しています。
施工してくれた職人さん方もとても愛想良くマナーもしっかりしており、塗り替えの仕上がり・接客応対ともに大満足の結果でした。

工事金額も他業者さんと比べても安価でしたし、是非とも京都で外壁塗装を検討されている方におすすめしたい優良塗装業者さんです。

株式会社ウェルビーホームさんを利用した方の評判・口コミ

40代・女性・京都市中京区在住

外壁塗装が初めての私にも非常に丁寧にご説明くださいました。
打ち合わせの時点から高橋社長の人柄の良さは伝わりました。
見積書の内容も細かく教えてくださり、初めての外壁塗装も安心して行えました、ありがとうございました。

50代・男性・京都府城陽市在住

問い合わせから施工までやりとりがとてもスムーズでした。
特に問い合わせから現地確認までの対応の早さは一番でした。
カラーシミュレーションなど、色決めも早かったです。
仕上がりも綺麗で大満足です。

50代・女性・大阪府寝屋川市在住

前回の工事代金より大幅に安かったので大変驚きました。
こんなことなら前回の塗装工事もウェルビーホームさんにお願いしたかったです。
次回の塗装もお願いしたいので、その際はよろしくお願いします。

京都で評判・口コミの良い外壁塗装業者ランキング
ランキング2位

京都で評判・口コミの良い外壁塗装業者ランキング

株式会社 佐藤塗装店

京都でおすすめの優良外壁塗装業者|株式会社 佐藤塗装店

株式会社 佐藤塗装店さんの特徴

「株式会社 佐藤塗装店」さんは、京都市西京区を中心に京都府全域、大阪府、滋賀県、奈良県と幅広いエリアで活躍する塗装業者さんです。

代表の佐藤さんは、「一級塗装技能士」の資格をはじめ、「一級左官技能士」「足場組立作業主任者」など、数多くの資格を有しておられます。
塗り替えを依頼する塗装業者さんが塗装だけでなく他の建築工事に関して精通していると、幅広い視点で的確なアドバイスをもらえるので嬉しいポイントです。

佐藤塗装店さんは、日本ペイント株式会社の特約店であり、使用する塗料も日本ペイントが主になりますので、塗料の単価や性能など、工事内容が非常に明確です。
見積もりの内容も分かりやすく明瞭会計で、職人さんの対応も非常に丁寧です。
京都の数ある塗装業者の中でも、5指に入る優良塗装業者さんです。

株式会社 佐藤塗装店さんを利用した方の評判・口コミ

50代・男性・京都市西京区在住

日本ペイントの塗料と聞いて安心しましたし、塗料の知識が豊富な営業さんで、勉強になりました。
価格がわかりやすく、日本ペイントの塗料を使用しているとのことで、決めました。
仕上がりにも大変満足です。

50代・女性・兵庫県神戸市在住

住まいのイメージを変えたく、相談に乗っていただきました。
熱心に対応して頂き、次回もお願いしたいと思います。
ありがとうございました。

40代・女性・大阪府堺市在住

塗装後玄関周りの色が気に入らず、再度塗り替えて頂き有難うございました。
大満足です。ご近所様をご紹介させて頂きます。

京都で評判・口コミの良い外壁塗装業者ランキング
ランキング3位

京都で評判・口コミの良い外壁塗装業者ランキング

株式会社 伊藤建装

京都でおすすめの優良外壁塗装業者|株式会社 伊藤建装

株式会社 伊藤建装さんの特徴

「株式会社 伊藤建装」さんは、京都市伏見区を中心に京都府・滋賀県・大阪府北部で活躍する塗装業者さんです。

「一級塗装技能士」の資格保有者だけでなく、外壁診断士や外壁アドバイザーなどの資格保有者が複数在籍しておられ、まさに外壁のプロフェッショナルです。
非常に多くの塗料・プランをご用意されており、外壁診断士さんがお住まい一軒一軒に合ったプランを提案してくれます。

非常に多くの職人さんが在籍され、宣伝・広告にも力を入れておられるので、工事金額自体は決して安価ではありません
しかし、外壁をしっかり診断してほしい・質の良い塗装工事をしてほしいといった、金額より施工品質重視の方にはおすすめの塗装業者さんです。

株式会社 伊藤建装さんを利用した方の評判・口コミ

40代・女性・京都市左京区在住

職人さん達はゴミの片付けもきっちりされていて良かったと思います。
女性の職人さんがいらっしゃったので驚きました。
足場を組む時なども男性と変わらない力強さで仕事をこなされていたので感心してました。

40代・男性・京都市西京区在住

細かいところまで綺麗にして頂き、ありがとうございました。
工事中、台風が来た時には困りましたが、結果的に綺麗に仕上げてくださり満足です。

50代・男性・滋賀県大津市在住

見積もりから施工まで、こまかいこだわりを重視してくださりありがとうございました。
家が生まれ変わったように綺麗になり感謝しています。
丁寧な職人さん達にも感謝です。

京都で評判・口コミの良い外壁塗装業者ランキング

京都でのおすすめ優良外壁塗装業者
1位:株式会社ウェルビーホーム
京都で評判・口コミの良い外壁塗装業者ランキング|株式会社ウェルビーホーム
京都でのおすすめ優良外壁塗装業者
2位:株式会社 佐藤塗装店
京京都で評判・口コミの良い外壁塗装業者ランキング|株式会社 佐藤塗装店
京都でのおすすめ優良外壁塗装業者
3位:株式会社 伊藤建装
京都で評判・口コミの良い外壁塗装業者ランキング|株式会社 伊藤建装

【免責事項】当サイトは、管理人が個人的に情報収集した内容を基に作成しています。最新の情報は各サイトにお問い合わせください。

© 京都の外壁塗装で選ぶべき評判・口コミの良い業者ランキング.