WordPress at a glance
function is not described

wpdb::prepare() public WP 2.3.0

Prepares a SQL query for safe execution.

Uses sprintf()-like syntax. The following placeholders can be used in the query string: %d (integer) %f (float) %s (string)

All placeholders MUST be left unquoted in the query string. A corresponding argument MUST be passed for each placeholder.

Note: There is one exception to the above: for compatibility with old behavior, numbered or formatted string placeholders (eg, %1$s, %5s) will not have quotes added by this function, so should be passed with appropriate quotes around them.

Literal percentage signs (%) in the query string must be written as %%. Percentage wildcards (for example, to use in LIKE syntax) must be passed via a substitution argument containing the complete LIKE string, these cannot be inserted directly in the query string. Also see wpdb::esc_like().

Arguments may be passed as individual arguments to the method, or as a single array containing all arguments. A combination of the two is not supported.

Examples:

$wpdb->prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s", array( 'foo', 1337, '%bar' ) );
$wpdb->prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );

{} It's a method of the class: wpdb{}

No Hooks.

Return

String|null. Sanitized query string, if there is a query to prepare.

Usage

global $wpdb;
$wpdb->prepare( $query, ...$args );
$query(string) (required)
Query statement with sprintf()-like placeholders.
...$args(mixed) (required)
Further variables to substitute into the query's placeholders if being called with individual arguments.

Changelog

Since 2.3.0 Introduced.
Since 5.3.0 Formalized the existing and already documented ...$args parameter by updating the function signature. The second parameter was changed from $args to ...$args.

Code of wpdb::prepare() WP 5.7.2

<?php
public function prepare( $query, ...$args ) {
	if ( is_null( $query ) ) {
		return;
	}

	// This is not meant to be foolproof -- but it will catch obviously incorrect usage.
	if ( strpos( $query, '%' ) === false ) {
		wp_load_translations_early();
		_doing_it_wrong(
			'wpdb::prepare',
			sprintf(
				/* translators: %s: wpdb::prepare() */
				__( 'The query argument of %s must have a placeholder.' ),
				'wpdb::prepare()'
			),
			'3.9.0'
		);
	}

	// If args were passed as an array (as in vsprintf), move them up.
	$passed_as_array = false;
	if ( is_array( $args[0] ) && count( $args ) === 1 ) {
		$passed_as_array = true;
		$args            = $args[0];
	}

	foreach ( $args as $arg ) {
		if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				sprintf(
					/* translators: %s: Value type. */
					__( 'Unsupported value type (%s).' ),
					gettype( $arg )
				),
				'4.8.2'
			);
		}
	}

	/*
	 * Specify the formatting allowed in a placeholder. The following are allowed:
	 *
	 * - Sign specifier. eg, $+d
	 * - Numbered placeholders. eg, %1$s
	 * - Padding specifier, including custom padding characters. eg, %05s, %'#5s
	 * - Alignment specifier. eg, %05-s
	 * - Precision specifier. eg, %.2f
	 */
	$allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|\'.)?[-+0-9]*(?:\.[0-9]+)?';

	/*
	 * If a %s placeholder already has quotes around it, removing the existing quotes and re-inserting them
	 * ensures the quotes are consistent.
	 *
	 * For backward compatibility, this is only applied to %s, and not to placeholders like %1$s, which are frequently
	 * used in the middle of longer strings, or as table name placeholders.
	 */
	$query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes.
	$query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes.
	$query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings like %%s.

	$query = preg_replace( "/(?<!%)(%($allowed_format)?f)/", '%\\2F', $query ); // Force floats to be locale-unaware.

	$query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF]))/", '%%\\1', $query ); // Escape any unescaped percents.

	// Count the number of valid placeholders in the query.
	$placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );

	$args_count = count( $args );

	if ( $args_count !== $placeholders ) {
		if ( 1 === $placeholders && $passed_as_array ) {
			// If the passed query only expected one argument, but the wrong number of arguments were sent as an array, bail.
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				__( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ),
				'4.9.0'
			);

			return;
		} else {
			/*
			 * If we don't have the right number of placeholders, but they were passed as individual arguments,
			 * or we were expecting multiple arguments in an array, throw a warning.
			 */
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				sprintf(
					/* translators: 1: Number of placeholders, 2: Number of arguments passed. */
					__( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
					$placeholders,
					$args_count
				),
				'4.8.3'
			);

			/*
			 * If we don't have enough arguments to match the placeholders,
			 * return an empty string to avoid a fatal error on PHP 8.
			 */
			if ( $args_count < $placeholders ) {
				$max_numbered_placeholder = ! empty( $matches[3] ) ? max( array_map( 'intval', $matches[3] ) ) : 0;

				if ( ! $max_numbered_placeholder || $args_count < $max_numbered_placeholder ) {
					return '';
				}
			}
		}
	}

	array_walk( $args, array( $this, 'escape_by_ref' ) );
	$query = vsprintf( $query, $args );

	return $this->add_placeholder_escape( $query );
}