message = $message; } public function get_error_message(): string { return $this->message; } } } if ( ! function_exists( 'sanitize_text_field' ) ) { /** * Minimal WordPress-compatible text sanitizer for unit tests. * * @param mixed $value Value to sanitize. * @return string */ function sanitize_text_field( $value ) { return trim( preg_replace( '/[\r\n\t]+/', ' ', wp_strip_all_tags( (string) $value ) ) ); } } if ( ! function_exists( 'sanitize_key' ) ) { /** * Minimal WordPress-compatible key sanitizer for unit tests. * * @param mixed $key Key to sanitize. * @return string */ function sanitize_key( $key ) { return strtolower( preg_replace( '/[^a-zA-Z0-9_\-]/', '', (string) $key ) ); } } if ( ! function_exists( 'wp_strip_all_tags' ) ) { /** * Minimal tag stripper for unit tests. * * @param string $value Value to strip. * @return string */ function wp_strip_all_tags( $value ) { return preg_replace( '/<[^>]*>/', '', $value ); } } if ( ! function_exists( 'wp_unslash' ) ) { /** * Minimal slashes remover for unit tests. * * @param mixed $value Value to unslash. * @return mixed */ function wp_unslash( $value ) { if ( is_array( $value ) ) { return array_map( 'wp_unslash', $value ); } return is_string( $value ) ? stripslashes( $value ) : $value; } } if ( ! function_exists( 'esc_html' ) ) { /** * Minimal HTML escaper for unit tests. * * @param mixed $value Value to escape. * @return string */ function esc_html( $value ) { return htmlspecialchars( (string) $value, ENT_QUOTES, 'UTF-8' ); } } if ( ! function_exists( '__' ) ) { /** * Minimal translation helper for unit tests. * * @param string $text Text to translate. * @param string $domain Text domain. * @return string */ function __( $text, $domain = 'default' ) { $GLOBALS['wpcs_test_text_domain'] = $domain; return $text; } } if ( ! function_exists( 'esc_html__' ) ) { /** * Minimal translated HTML escaper for unit tests. * * @param string $text Text to translate and escape. * @param string $domain Text domain. * @return string */ function esc_html__( $text, $domain = 'default' ) { $GLOBALS['wpcs_test_text_domain'] = $domain; return esc_html( $text ); } } if ( ! function_exists( 'esc_attr' ) ) { /** * Minimal attribute escaper for unit tests. * * @param mixed $value Value to escape. * @return string */ function esc_attr( $value ) { return htmlspecialchars( (string) $value, ENT_QUOTES, 'UTF-8' ); } } if ( ! function_exists( 'esc_url' ) ) { /** * Minimal URL sanitizer for unit tests. * * @param mixed $value Value to sanitize. * @return string */ function esc_url( $value ) { return filter_var( (string) $value, FILTER_SANITIZE_URL ); } } if ( ! function_exists( 'esc_url_raw' ) ) { /** * Minimal raw URL sanitizer for unit tests. * * @param mixed $value Value to sanitize. * @return string */ function esc_url_raw( $value ) { return filter_var( (string) $value, FILTER_SANITIZE_URL ); } } if ( ! function_exists( 'wp_parse_url' ) ) { /** * Minimal URL parser for unit tests. * * @param string $url URL to parse. * @return array|false */ function wp_parse_url( $url ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- Test stub for WordPress' wp_parse_url(). return parse_url( $url ); } } if ( ! function_exists( 'wp_json_encode' ) ) { /** * Minimal JSON encoder for unit tests. * * @param mixed $value Value to encode. * @param int $flags JSON encoding flags. * @return string|false */ function wp_json_encode( $value, $flags = 0 ) { // phpcs:ignore -- Test stub for WordPress' wp_json_encode(). return json_encode( $value, $flags ); } } if ( ! function_exists( 'get_option' ) ) { /** * Minimal WordPress option reader for unit tests. * * @param string $name Option name. * @param mixed $default_value Default value. * @return mixed */ function get_option( $name, $default_value = false ) { return $GLOBALS['wpcs_test_options'][ $name ] ?? $default_value; } } if ( ! function_exists( 'update_option' ) ) { /** * Minimal WordPress option writer for unit tests. * * @param string $name Option name. * @param mixed $value Option value. * @param mixed $autoload Autoload flag. * @return bool */ function update_option( $name, $value, $autoload = null ) { $GLOBALS['wpcs_test_options'][ $name ] = $value; $GLOBALS['wpcs_test_option_autoloads'][ $name ] = $autoload; return true; } } if ( ! function_exists( 'delete_transient' ) ) { /** * Minimal WordPress transient deleter for unit tests. * * @param string $name Transient name. * @return bool */ function delete_transient( $name ) { unset( $GLOBALS['wpcs_test_transients'][ $name ] ); unset( $GLOBALS['wpcs_test_transient_expiration'][ $name ] ); return true; } } if ( ! function_exists( 'get_transient' ) ) { /** * Minimal WordPress transient reader for unit tests. * * @param string $name Transient name. * @return mixed */ function get_transient( $name ) { return $GLOBALS['wpcs_test_transients'][ $name ] ?? false; } } if ( ! function_exists( 'set_transient' ) ) { /** * Minimal WordPress transient writer for unit tests. * * @param string $name Transient name. * @param mixed $value Transient value. * @param int $expiration Expiration in seconds. * @return bool */ function set_transient( $name, $value, $expiration = 0 ) { $GLOBALS['wpcs_test_transients'][ $name ] = $value; $GLOBALS['wpcs_test_transient_expiration'][ $name ] = $expiration; return true; } } if ( ! function_exists( 'plugin_dir_path' ) ) { /** * Minimal plugin path helper for static analysis. * * @param string $file Plugin file. * @return string */ function plugin_dir_path( $file ) { return trailingslashit( dirname( $file ) ); } } if ( ! function_exists( 'plugin_dir_url' ) ) { /** * Minimal plugin URL helper for static analysis. * * @param string $file Plugin file. * @return string */ function plugin_dir_url( $file ) { return 'http://example.org/wp-content/plugins/' . basename( dirname( $file ) ) . '/'; } } if ( ! function_exists( 'trailingslashit' ) ) { /** * Minimal trailing slash helper for static analysis. * * @param string $value Value to slash. * @return string */ function trailingslashit( $value ) { return rtrim( $value, '/\\' ) . DIRECTORY_SEPARATOR; } } if ( ! function_exists( 'register_activation_hook' ) ) { /** * Minimal activation hook registrar for static analysis. * * @param string $file Plugin file. * @param callable $callback Activation callback. * @return void */ function register_activation_hook( $file, $callback ) { $GLOBALS['wpcs_test_activation_hooks'][ $file ] = $callback; } } if ( ! function_exists( 'register_deactivation_hook' ) ) { /** * Minimal deactivation hook registrar for static analysis. * * @param string $file Plugin file. * @param callable $callback Deactivation callback. * @return void */ function register_deactivation_hook( $file, $callback ) { $GLOBALS['wpcs_test_deactivation_hooks'][ $file ] = $callback; } } if ( ! function_exists( 'add_action' ) ) { /** * Minimal action registrar for static analysis. * * @param string $hook_name Hook name. * @param callable $callback Hook callback. * @return bool */ function add_action( $hook_name, $callback ) { $GLOBALS['wpcs_test_actions'][ $hook_name ][] = $callback; return true; } } if ( ! function_exists( 'add_management_page' ) ) { /** * Minimal management page registrar for static analysis. * * @param string $page_title Page title. * @param string $menu_title Menu title. * @param string $capability Capability required. * @param string $menu_slug Menu slug. * @param callable $callback Page callback. * @return string */ function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $callback ) { $GLOBALS['wpcs_test_admin_pages'][ $menu_slug ] = array( 'page_title' => $page_title, 'menu_title' => $menu_title, 'capability' => $capability, 'callback' => $callback, ); return $menu_slug; } } if ( ! function_exists( 'register_setting' ) ) { /** * Minimal setting registrar for static analysis. * * @param string $option_group Option group. * @param string $option_name Option name. * @param array $args Setting arguments. * @return bool */ function register_setting( $option_group, $option_name, $args = array() ) { $GLOBALS['wpcs_test_registered_settings'][ $option_name ] = array( 'option_group' => $option_group, 'args' => $args, ); return true; } } if ( ! function_exists( 'current_user_can' ) ) { /** * Minimal capability checker for static analysis. * * @param string $capability Capability to check. * @return bool */ function current_user_can( $capability ) { return $GLOBALS['wpcs_current_user_can'][ $capability ] ?? 'manage_options' === $capability; } } if ( ! function_exists( 'check_admin_referer' ) ) { /** * Minimal nonce checker for unit tests. * * @param string $action Nonce action. * @param string $query_arg Nonce request field. * @return bool */ function check_admin_referer( $action, $query_arg = '_wpnonce' ) { return $GLOBALS['wpcs_nonce_valid'][ $action ][ $query_arg ] ?? true; } } if ( ! function_exists( 'wp_safe_redirect' ) ) { /** * Minimal safe redirect helper for unit tests. * * @param string $location Redirect location. * @return bool */ function wp_safe_redirect( $location ) { $GLOBALS['wpcs_redirect_location'] = $location; return true; } } if ( ! function_exists( 'wp_remote_get' ) ) { /** * Minimal HTTP GET helper for unit tests. * * @param string $url Request URL. * @param array $args Request arguments. * @return array|\WP_Error */ function wp_remote_get( $url, array $args = array() ) { $GLOBALS['wpcs_last_http_request'] = array( 'method' => 'GET', 'url' => $url, 'args' => $args, ); return $GLOBALS['wpcs_http_response'] ?? array( 'response' => array( 'code' => 200 ), 'body' => '{"ok":true}', ); } } if ( ! function_exists( 'wp_remote_post' ) ) { /** * Minimal HTTP POST helper for unit tests. * * @param string $url Request URL. * @param array $args Request arguments. * @return array|\WP_Error */ function wp_remote_post( $url, array $args = array() ) { $GLOBALS['wpcs_last_http_request'] = array( 'method' => 'POST', 'url' => $url, 'args' => $args, ); return $GLOBALS['wpcs_http_response'] ?? array( 'response' => array( 'code' => 200 ), 'body' => '{"accepted":true}', ); } } if ( ! function_exists( 'wp_remote_retrieve_response_code' ) ) { /** * Minimal response code helper for unit tests. * * @param array $response HTTP response. * @return int */ function wp_remote_retrieve_response_code( array $response ) { return (int) ( $response['response']['code'] ?? 0 ); } } if ( ! function_exists( 'wp_remote_retrieve_body' ) ) { /** * Minimal response body helper for unit tests. * * @param array $response HTTP response. * @return string */ function wp_remote_retrieve_body( array $response ) { return (string) ( $response['body'] ?? '' ); } } if ( ! function_exists( 'is_wp_error' ) ) { /** * Minimal WP_Error checker for unit tests. * * @param mixed $value Value to check. * @return bool */ function is_wp_error( $value ) { return $value instanceof WP_Error; } } if ( ! function_exists( 'register_rest_route' ) ) { /** * Minimal REST route registrar for unit tests. * * @param string $rest_namespace REST namespace. * @param string $route REST route. * @param array $args Route arguments. * @return bool */ function register_rest_route( $rest_namespace, $route, array $args ) { $GLOBALS['wpcs_rest_routes'][ $rest_namespace . $route ] = $args; return true; } } if ( ! function_exists( 'rest_ensure_response' ) ) { /** * Minimal REST response wrapper for unit tests. * * @param mixed $response Response value. * @return mixed */ function rest_ensure_response( $response ) { return $response; } } if ( ! function_exists( 'wp_insert_post' ) ) { /** * Minimal post inserter for unit tests. * * @param array $postarr Post data. * @param bool $wp_error Whether to return WP_Error on failure. * @return int|\WP_Error */ function wp_insert_post( array $postarr, $wp_error = false ) { if ( empty( $postarr['post_type'] ) ) { return $wp_error ? new WP_Error( 'invalid_post_type', 'Post type is required.' ) : 0; } if ( isset( $postarr['ID'] ) && (int) $postarr['ID'] > 0 ) { $post_id = (int) $postarr['ID']; } else { $post_id = (int) ( $GLOBALS['wpcs_test_next_post_id'] ?? 1 ); $GLOBALS['wpcs_test_next_post_id'] = $post_id + 1; } if ( $post_id <= 0 && $wp_error ) { return new WP_Error( 'invalid_post_id', 'Post ID is invalid.' ); } $GLOBALS['wpcs_test_posts'][ $post_id ] = array_merge( array( 'ID' => $post_id, 'post_title' => '', 'post_content' => '', 'post_excerpt' => '', 'post_status' => 'draft', 'post_type' => 'post', 'post_name' => '', 'post_parent' => 0, 'menu_order' => 0, 'post_mime_type' => '', ), $postarr, array( 'ID' => $post_id ) ); return $post_id; } } if ( ! function_exists( 'wp_update_post' ) ) { /** * Minimal post updater for unit tests. * * @param array $postarr Post data. * @param bool $wp_error Whether to return WP_Error on failure. * @return int|\WP_Error */ function wp_update_post( array $postarr, $wp_error = false ) { $post_id = (int) ( $postarr['ID'] ?? 0 ); if ( $post_id <= 0 || ! isset( $GLOBALS['wpcs_test_posts'][ $post_id ] ) ) { return $wp_error ? new WP_Error( 'invalid_post_id', 'Post does not exist.' ) : 0; } $GLOBALS['wpcs_test_posts'][ $post_id ] = array_merge( $GLOBALS['wpcs_test_posts'][ $post_id ], $postarr, array( 'ID' => $post_id ) ); return $post_id; } } if ( ! function_exists( 'get_post' ) ) { /** * Minimal post reader for unit tests. * * @param mixed $post Post ID. * @param string $output Output format. * @param string $filter Filter context. * @return array|object|null */ function get_post( $post = null, $output = 'ARRAY_A', $filter = 'raw' ) { $GLOBALS['wpcs_test_post_filter'] = $filter; $post_id = (int) $post; $data = $GLOBALS['wpcs_test_posts'][ $post_id ] ?? null; if ( null === $data ) { return null; } return 'OBJECT' === $output ? (object) $data : $data; } } if ( ! function_exists( 'get_posts' ) ) { /** * Minimal posts query for unit tests. * * @param array $args Query args. * @return array */ function get_posts( array $args = array() ) { $posts = array_values( $GLOBALS['wpcs_test_posts'] ?? array() ); if ( isset( $args['post_type'] ) && 'any' !== $args['post_type'] ) { $post_types = is_array( $args['post_type'] ) ? $args['post_type'] : array( $args['post_type'] ); $posts = array_filter( $posts, static function ( array $post ) use ( $post_types ): bool { return in_array( $post['post_type'] ?? '', $post_types, true ); } ); } if ( isset( $args['meta_key'], $args['meta_value'] ) ) { $posts = array_filter( $posts, static function ( array $post ) use ( $args ): bool { $values = $GLOBALS['wpcs_test_post_meta'][ (int) $post['ID'] ][ (string) $args['meta_key'] ] ?? array(); foreach ( $values as $value ) { if ( (string) $args['meta_value'] === (string) $value ) { return true; } } return false; } ); } return array_values( array_map( static fn( array $post ): object => (object) $post, $posts ) ); } } if ( ! function_exists( 'wp_delete_post' ) ) { /** * Minimal post deleter for unit tests. * * @param int $post_id Post ID. * @param bool $force_delete Force delete flag. * @return bool */ function wp_delete_post( $post_id, $force_delete = false ) { $GLOBALS['wpcs_test_force_delete'][ (int) $post_id ] = (bool) $force_delete; unset( $GLOBALS['wpcs_test_posts'][ (int) $post_id ] ); unset( $GLOBALS['wpcs_test_post_meta'][ (int) $post_id ] ); return true; } } if ( ! function_exists( 'update_post_meta' ) ) { /** * Minimal post meta updater for unit tests. * * @param int $post_id Post ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. * @return bool */ function update_post_meta( $post_id, $meta_key, $meta_value ) { $GLOBALS['wpcs_test_post_meta'][ (int) $post_id ][ (string) $meta_key ] = array( $meta_value ); return true; } } if ( ! function_exists( 'get_post_meta' ) ) { /** * Minimal post meta reader for unit tests. * * @param int $post_id Post ID. * @param string $key Meta key. * @param bool $single Whether to return single value. * @return mixed */ function get_post_meta( $post_id, $key = '', $single = false ) { $meta = $GLOBALS['wpcs_test_post_meta'][ (int) $post_id ] ?? array(); if ( '' === $key ) { return $meta; } $values = $meta[ $key ] ?? array(); if ( $single ) { return $values[0] ?? ''; } return $values; } } if ( ! function_exists( 'delete_post_meta' ) ) { /** * Minimal post meta deleter for unit tests. * * @param int $post_id Post ID. * @param string $meta_key Meta key. * @return bool */ function delete_post_meta( $post_id, $meta_key ) { unset( $GLOBALS['wpcs_test_post_meta'][ (int) $post_id ][ (string) $meta_key ] ); return true; } } if ( ! function_exists( 'wp_insert_term' ) ) { /** * Minimal term inserter for unit tests. * * @param string $term Term name. * @param string $taxonomy Taxonomy. * @param array $args Term args. * @return array|\WP_Error */ function wp_insert_term( $term, $taxonomy, array $args = array() ) { if ( '' === (string) $term || '' === (string) $taxonomy ) { return new WP_Error( 'invalid_term', 'Term name and taxonomy are required.' ); } $term_id = (int) ( $GLOBALS['wpcs_test_next_term_id'] ?? 1 ); $GLOBALS['wpcs_test_next_term_id'] = $term_id + 1; $slug = (string) ( $args['slug'] ?? sanitize_key( $term ) ); $GLOBALS['wpcs_test_terms'][ $term_id ] = array( 'term_id' => $term_id, 'term_taxonomy_id' => $term_id, 'name' => (string) $term, 'taxonomy' => (string) $taxonomy, 'slug' => $slug, 'description' => (string) ( $args['description'] ?? '' ), 'parent' => (int) ( $args['parent'] ?? 0 ), ); return array( 'term_id' => $term_id, 'term_taxonomy_id' => $term_id, ); } } if ( ! function_exists( 'wp_update_term' ) ) { /** * Minimal term updater for unit tests. * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy. * @param array $args Term args. * @return array|\WP_Error */ function wp_update_term( $term_id, $taxonomy, array $args = array() ) { $term_id = (int) $term_id; if ( ! isset( $GLOBALS['wpcs_test_terms'][ $term_id ] ) ) { return new WP_Error( 'invalid_term_id', 'Term does not exist.' ); } $GLOBALS['wpcs_test_terms'][ $term_id ] = array_merge( $GLOBALS['wpcs_test_terms'][ $term_id ], $args, array( 'term_id' => $term_id, 'term_taxonomy_id' => $term_id, 'taxonomy' => (string) $taxonomy, ) ); return array( 'term_id' => $term_id, 'term_taxonomy_id' => $term_id, ); } } if ( ! function_exists( 'get_term_by' ) ) { /** * Minimal term reader for unit tests. * * @param string $field Field name. * @param mixed $value Field value. * @param string $taxonomy Taxonomy. * @return array|false */ function get_term_by( $field, $value, $taxonomy ) { foreach ( $GLOBALS['wpcs_test_terms'] ?? array() as $term ) { if ( (string) ( $term['taxonomy'] ?? '' ) !== (string) $taxonomy ) { continue; } if ( isset( $term[ $field ] ) && (string) $value === (string) $term[ $field ] ) { return $term; } } return false; } } if ( ! function_exists( 'wp_set_object_terms' ) ) { /** * Minimal object term relationship setter for unit tests. * * @param int $object_id Object ID. * @param string|array $terms Terms. * @param string $taxonomy Taxonomy. * @return array */ function wp_set_object_terms( $object_id, $terms, $taxonomy ) { $term_values = is_array( $terms ) ? array_values( $terms ) : array( $terms ); $GLOBALS['wpcs_test_object_terms'][ (int) $object_id ][ (string) $taxonomy ] = $term_values; return $term_values; } } if ( ! function_exists( 'wp_insert_attachment' ) ) { /** * Minimal attachment inserter for unit tests. * * @param array $args Attachment args. * @param mixed $file File path. * @param int $parent_post_id Parent post ID. * @param bool $wp_error Whether to return WP_Error on failure. * @return int|\WP_Error */ function wp_insert_attachment( array $args, $file = false, $parent_post_id = 0, $wp_error = false ) { $GLOBALS['wpcs_test_attachment_files'][] = $file; $args['post_type'] = 'attachment'; $args['post_parent'] = (int) $parent_post_id; return wp_insert_post( $args, $wp_error ); } } if ( ! function_exists( 'wp_update_attachment_metadata' ) ) { /** * Minimal attachment metadata updater for unit tests. * * @param int $attachment_id Attachment ID. * @param mixed $data Metadata. * @return bool */ function wp_update_attachment_metadata( $attachment_id, $data ) { $GLOBALS['wpcs_test_attachment_metadata'][ (int) $attachment_id ] = $data; return true; } } if ( ! function_exists( 'wp_get_attachment_metadata' ) ) { /** * Minimal attachment metadata reader for unit tests. * * @param int $attachment_id Attachment ID. * @return mixed */ function wp_get_attachment_metadata( $attachment_id ) { return $GLOBALS['wpcs_test_attachment_metadata'][ (int) $attachment_id ] ?? false; } } if ( ! function_exists( 'admin_url' ) ) { /** * Minimal admin URL helper for unit tests. * * @param string $path Admin path. * @return string */ function admin_url( $path = '' ) { return 'https://example.test/wp-admin/' . ltrim( $path, '/' ); } } if ( ! function_exists( 'add_query_arg' ) ) { /** * Minimal query arg helper for unit tests. * * @param array $args Query args. * @param string $url URL. * @return string */ function add_query_arg( array $args, $url ) { return $url . ( false === strpos( $url, '?' ) ? '?' : '&' ) . http_build_query( $args ); } } if ( ! function_exists( 'wp_nonce_field' ) ) { /** * Minimal nonce field renderer for unit tests. * * @param string $action Nonce action. * @param string $name Field name. * @return void */ function wp_nonce_field( $action, $name ) { echo ''; } } if ( ! function_exists( 'submit_button' ) ) { /** * Minimal submit button renderer for unit tests. * * @param string $text Button text. * @param string $type Button type. * @return void */ function submit_button( $text, $type = 'primary' ) { echo ''; } } if ( ! function_exists( 'wp_die' ) ) { /** * Minimal WordPress die handler for unit tests. * * @param mixed $message Message to die with. * @return void * * @throws \RuntimeException Always throws with the provided message. */ function wp_die( $message ) { throw new \RuntimeException( esc_html( $message ) ); } }