Repository: wp-graphql/wp-graphql (PHP)

Issue:
MediaItemSizeEnum becomes empty when intermediate image sizes are disabled → schema invalid
### Description

When WordPress runs with all intermediate image sizes disabled (policy on WordPress VIP), WPGraphQL exposes MediaItemSizeEnum with zero values. This produces an invalid GraphQL schema and breaks tools that consume introspection (e.g., graphql-codegen) with:
Enum type MediaItemSizeEnum must define one or more values.
Older WPGraphQL bundled with VIP included fallbacks so the enum wasn’t empty; newer standalone builds appear to have removed that behavior.

### Steps to reproduce

Run WP with no intermediate sizes (e.g., remove/disable all registered sizes so get_intermediate_image_sizes() returns []). On VIP this is default policy.

Install/activate standalone WPGraphQL (recent release).

Introspect schema or hit /graphql and inspect MediaItemSizeEnum.

Run any codegen/validation on the schema.

### Additional context

_No response_

### WPGraphQL Version

2.3.6

### WordPress Version

6.8.3

### PHP Version

8.2

### Additional environment details

_No response_

### Please confirm that you have searched existing issues in the repo.

- [x] Yes

### Please confirm that you have disabled ALL plugins except for WPGraphQL.

- [ ] Yes
- [ ] My issue is with compatibility with a specific WordPress plugin, and I have listed all my installed plugins (and version info) above.


Discussion: @tloureiro Thanks for opening this issue and providing context and steps to reproduce! 

I am working on a PR and hope to have something ready shortly. 



Fix (patch):
diff --git a/phpcs/WPGraphQL/PHPCS/Sniffs/Functions/VersionParameterSniff.php b/phpcs/WPGraphQL/PHPCS/Sniffs/Functions/VersionParameterSniff.php
index 3d535b77c..d8198b548 100644
--- a/phpcs/WPGraphQL/PHPCS/Sniffs/Functions/VersionParameterSniff.php
+++ b/phpcs/WPGraphQL/PHPCS/Sniffs/Functions/VersionParameterSniff.php
@@ -35,9 +35,9 @@ class VersionParameterSniff implements Sniff
      * @var array<string>
      */
     private $validPlaceholders = [
+        '@next-version',
         '@since next-version',
         '@since todo',
-        '@next-version',
     ];
 
     public function __construct()
@@ -108,9 +108,9 @@ public function process(File $phpcsFile, $stackPtr)
 
         // Check if it's a valid placeholder
         if (in_array($version, $this->validPlaceholders, true)) {
-            if ($version !== '@since next-version') {
+            if ($version !== '@next-version') {
                 $fix = $phpcsFile->addFixableWarning(
-                    'Please use "@since next-version" instead of "%s"',
+                    'Please use "@next-version" instead of "%s" for function parameters',
                     $parameters[$paramPosition - 1]['start'],
                     'OldVersionPlaceholder',
                     [$version]
@@ -126,7 +126,7 @@ public function process(File $phpcsFile, $stackPtr)
         // Validate semver
         if (!$this->isValidSemver($version)) {
             $fix = $phpcsFile->addFixableError(
-                'Invalid version "%s" in %s(). Must be a valid semver version or "@since next-version"',
+                'Invalid version "%s" in %s(). Must be a valid semver version or "@next-version"',
                 $parameters[$paramPosition - 1]['start'],
                 'InvalidVersion',
                 [$version, $functionName]
@@ -232,7 +232,7 @@ private function fixVersionParameter(File $phpcsFile, array $parameter)
         }
 
         $phpcsFile->fixer->beginChangeset();
-        $phpcsFile->fixer->replaceToken($parameter['start'], "'@since next-version'");
+        $phpcsFile->fixer->replaceToken($parameter['start'], "'@next-version'");
 
         // Clear any remaining tokens
         for ($i = $parameter['start'] + 1; $i <= $parameter['end']; $i++) {
diff --git a/src/AppContext.php b/src/AppContext.php
index 5763fdb39..3cb0ea493 100644
--- a/src/AppContext.php
+++ b/src/AppContext.php
@@ -359,7 +359,7 @@ public function __set( $name, $value ) {
 					esc_html__( 'Setting dynamic properties on AppContext is deprecated. Use AppContext::set() instead. Attempted to set property: %s', 'wp-graphql' ),
 					esc_html( $name )
 				),
-				'@since 2.3.8'
+				'2.3.8'
 			);
 		}
 
diff --git a/src/Experimental/ExperimentRegistry.php b/src/Experimental/ExperimentRegistry.php
index 69b873cbc..266581788 100644
--- a/src/Experimental/ExperimentRegistry.php
+++ b/src/Experimental/ExperimentRegistry.php
@@ -80,7 +80,7 @@ public static function get_experiment_registry(): array {
 			_doing_it_wrong(
 				__METHOD__,
 				esc_html__( 'Registered experiments have not been set. Make sure not to call this function before the `graphql_experiments_registered` hook.', 'wp-graphql' ),
-				'@since 2.3.8'
+				'2.3.8'
 			);
 
 			return [];
@@ -99,7 +99,7 @@ public static function get_experiments(): array {
 			_doing_it_wrong(
 				__METHOD__,
 				esc_html__( 'Experiments have not been loaded. Make sure not to call this function before the `graphql_experiments_loaded` hook.', 'wp-graphql' ),
-				'@since 2.3.8'
+				'2.3.8'
 			);
 
 			return [];
@@ -118,7 +118,7 @@ public static function get_active_experiments(): array {
 			_doing_it_wrong(
 				__METHOD__,
 				esc_html__( 'Active experiments have not been loaded. Make sure not to call this function before the `graphql_experiments_loaded` hook.', 'wp-graphql' ),
-				'@since 2.3.8'
+				'2.3.8'
 			);
 
 			return [];
diff --git a/src/Type/Enum/MediaItemSizeEnum.php b/src/Type/Enum/MediaItemSizeEnum.php
index 7d166dc52..33f3db1ae 100644
--- a/src/Type/Enum/MediaItemSizeEnum.php
+++ b/src/Type/Enum/MediaItemSizeEnum.php
@@ -36,6 +36,40 @@ protected static function get_image_sizes( $size = '' ): ?array {
 			}
 		}
 
+		/**
+		 * If no sizes were found (e.g., on WordPress VIP where intermediate sizes are disabled),
+		 * populate with standard WordPress image sizes as fallbacks.
+		 *
+		 * This ensures MediaItemSizeEnum always has at least one value, which is required by the
+		 * GraphQL specification. Enums must define one or more values.
+		 *
+		 * These fallback sizes represent standard WordPress image sizes that can be used as hints
+		 * when querying media items. WordPress core resolvers (like wp_get_attachment_image_src)
+		 * gracefully handle cases where requested sizes don't exist by falling back to available sizes.
+		 *
+		 * @see https://github.com/wp-graphql/wp-graphql/issues/3432
+		 */
+		if ( empty( $sizes ) ) {
+			// Define standard WordPress image sizes as fallbacks
+			$fallback_sizes = [ 'thumbnail', 'medium', 'medium_large', 'large', 'full' ];
+
+			foreach ( $fallback_sizes as $fallback_size ) {
+				if ( 'full' === $fallback_size ) {
+					// 'full' represents the original uploaded image and doesn't have fixed dimensions
+					$sizes[ $fallback_size ] = [
+						'width'  => 0,
+						'height' => 0,
+						'crop'   => false,
+					];
+				} else {
+					// Get dimensions from WordPress options for standard sizes
+					$sizes[ $fallback_size ]['width']  = \get_option( $fallback_size . '_size_w' );
+					$sizes[ $fallback_size ]['height'] = \get_option( $fallback_size . '_size_h' );
+					$sizes[ $fallback_size ]['crop']   = (bool) \get_option( $fallback_size . '_crop' );
+				}
+			}
+		}
+
 		// Get only 1 size if found
 		if ( $size ) {
 			if ( isset( $sizes[ $size ] ) ) {
@@ -54,7 +88,9 @@ protected static function get_image_sizes( $size = '' ): ?array {
 	 */
 	public static function register_type() {
 		/**
-		 * This returns an empty array on the VIP Go platform.
+		 * Get available image sizes. This may return an empty array on platforms
+		 * like WordPress VIP, but get_image_sizes() now provides fallback values
+		 * to ensure the enum always has at least one value.
 		 */
 		$sizes = self::get_image_sizes();