[wp-trac] [WordPress Trac] #64406: PHP 8.x TypeError in wp_delete_object_term_relationships() when taxonomy not registered

WordPress Trac noreply at wordpress.org
Fri Dec 12 05:30:26 UTC 2025


#64406: PHP 8.x TypeError in wp_delete_object_term_relationships() when taxonomy
not registered
----------------------------+------------------------------
 Reporter:  owolter         |       Owner:  (none)
     Type:  defect (bug)    |      Status:  new
 Priority:  normal          |   Milestone:  Awaiting Review
Component:  Taxonomy        |     Version:  6.9
 Severity:  normal          |  Resolution:
 Keywords:  php8 has-patch  |     Focuses:
----------------------------+------------------------------
Description changed by westonruter:

Old description:

> # WordPress Core Bug Report
>
> ## Summary
> PHP 8.x TypeError in `wp_delete_object_term_relationships()` when
> taxonomy is not registered during deletion
>
> ## Description
> The function `wp_delete_object_term_relationships()` in `wp-
> includes/taxonomy.php` does not check if `wp_get_object_terms()` returns
> a `WP_Error` object before passing the result to `array_map()`. This
> causes a fatal TypeError in PHP 8.0+ when attempting to delete
> attachments if a taxonomy is not properly registered at the time of the
> AJAX request.
>
> ## Steps to Reproduce
> 1. Have a WordPress installation with custom attachment taxonomies
> 2. Create a scenario where `post_tag` (or another taxonomy) is not
> registered during admin AJAX calls (e.g., through plugin load order
> issues, early AJAX execution)
> 3. Attempt to delete a media library item via wp-admin
> 4. Fatal error occurs
>
> ## Expected Behavior
> Attachment deletion should complete successfully even if a taxonomy
> returns a `WP_Error`, or at minimum should fail gracefully with a logged
> error rather than a fatal PHP error.
>
> ## Actual Behavior
> Fatal TypeError crashes the deletion process:
> ```
> PHP Fatal error: Uncaught TypeError: array_map(): Argument #2 ($array)
> must be of type array, WP_Error given in /wp-includes/taxonomy.php:2002
> Stack trace:
> #0 /wp-includes/taxonomy.php(2002): array_map()
> #1 /wp-includes/post.php(6743): wp_delete_object_term_relationships()
> #2 /wp-includes/post.php(3799): wp_delete_attachment()
> #3 /wp-admin/includes/ajax-actions.php(889): wp_delete_post()
> ```
>
> ## Technical Details
>
> **WordPress Version:** 6.9
> **PHP Version:** 8.3 (also affects 8.0, 8.1, 8.2, 8.4)
> **File:** `wp-includes/taxonomy.php`
> **Line:** ~2002
> **Function:** `wp_delete_object_term_relationships()`
>
> ### Root Cause
> The WordPress Codex documents that `wp_get_object_terms()` can return
> `WP_Error`, but `wp_delete_object_term_relationships()` assumes it always
> returns an array. In PHP 7.x this would fail silently or produce a
> warning, but PHP 8.x's strict type checking for built-in functions makes
> this a fatal error.
>
> **Current code (lines 1999-2003):**
> ```php
> foreach ( (array) $taxonomies as $taxonomy ) {
>     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
> 'fields' => 'ids' ) );
>     $term_ids = array_map( 'intval', $term_ids );
>     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
> }
> ```
>
> ## Proposed Fix
> Add a `WP_Error` check before calling `array_map()`:
>
> ```php
> foreach ( (array) $taxonomies as $taxonomy ) {
>     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
> 'fields' => 'ids' ) );
>     if ( is_wp_error( $term_ids ) ) {
>         continue;
>     }
>     $term_ids = array_map( 'intval', $term_ids );
>     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
> }
> ```
>
> Alternatively, for better debugging:
> ```php
> foreach ( (array) $taxonomies as $taxonomy ) {
>     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
> 'fields' => 'ids' ) );
>     if ( is_wp_error( $term_ids ) ) {
>         // Log error but continue deletion process
>         error_log( sprintf(
>             'Error retrieving terms for taxonomy "%s" on object %d: %s',
>             $taxonomy,
>             $object_id,
>             $term_ids->get_error_message()
>         ) );
>         continue;
>     }
>     $term_ids = array_map( 'intval', $term_ids );
>     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
> }
> ```
>
> ## Impact
> This is a **defensive programming issue**. While the underlying cause
> (taxonomy not registered) may vary by installation, WordPress core should
> handle `WP_Error` returns from its own functions gracefully rather than
> causing fatal errors. This affects PHP 8.0+ users and will become more
> prevalent as PHP 7.x reaches end-of-life.
>
> ## Additional Context
> This issue was discovered when attempting to delete media library items
> on a WordPress 6.9 installation running PHP 8.3. The error occurred
> because `post_tag` taxonomy was not registered during the AJAX deletion
> request, causing `wp_get_object_terms()` to return a `WP_Error` with the
> message "Invalid taxonomy".
>
> While the specific trigger may be environment-dependent, the lack of
> error handling is a core issue that should be addressed for PHP 8.x
> compatibility and general code robustness.

New description:

 # WordPress Core Bug Report

 = Summary
 PHP 8.x TypeError in `wp_delete_object_term_relationships()` when taxonomy
 is not registered during deletion

 == Description
 The function `wp_delete_object_term_relationships()` in `wp-
 includes/taxonomy.php` does not check if `wp_get_object_terms()` returns a
 `WP_Error` object before passing the result to `array_map()`. This causes
 a fatal TypeError in PHP 8.0+ when attempting to delete attachments if a
 taxonomy is not properly registered at the time of the AJAX request.

 == Steps to Reproduce
 1. Have a WordPress installation with custom attachment taxonomies
 2. Create a scenario where `post_tag` (or another taxonomy) is not
 registered during admin AJAX calls (e.g., through plugin load order
 issues, early AJAX execution)
 3. Attempt to delete a media library item via wp-admin
 4. Fatal error occurs

 == Expected Behavior
 Attachment deletion should complete successfully even if a taxonomy
 returns a `WP_Error`, or at minimum should fail gracefully with a logged
 error rather than a fatal PHP error.

 == Actual Behavior
 Fatal TypeError crashes the deletion process:

 {{{
 PHP Fatal error: Uncaught TypeError: array_map(): Argument #2 ($array)
 must be of type array, WP_Error given in /wp-includes/taxonomy.php:2002
 Stack trace:
 #0 /wp-includes/taxonomy.php(2002): array_map()
 #1 /wp-includes/post.php(6743): wp_delete_object_term_relationships()
 #2 /wp-includes/post.php(3799): wp_delete_attachment()
 #3 /wp-admin/includes/ajax-actions.php(889): wp_delete_post()
 }}}

 == Technical Details

 **WordPress Version:** 6.9
 **PHP Version:** 8.3 (also affects 8.0, 8.1, 8.2, 8.4)
 **File:** `wp-includes/taxonomy.php`
 **Line:** ~2002
 **Function:** `wp_delete_object_term_relationships()`

 === Root Cause
 The WordPress Codex documents that `wp_get_object_terms()` can return
 `WP_Error`, but `wp_delete_object_term_relationships()` assumes it always
 returns an array. In PHP 7.x this would fail silently or produce a
 warning, but PHP 8.x's strict type checking for built-in functions makes
 this a fatal error.

 **Current code (lines 1999-2003):**

 {{{#!php
 <?php
 foreach ( (array) $taxonomies as $taxonomy ) {
     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
 'fields' => 'ids' ) );
     $term_ids = array_map( 'intval', $term_ids );
     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
 }
 }}}


 == Proposed Fix
 Add a `WP_Error` check before calling `array_map()`:

 {{{#!php
 <?php
 foreach ( (array) $taxonomies as $taxonomy ) {
     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
 'fields' => 'ids' ) );
     if ( is_wp_error( $term_ids ) ) {
         continue;
     }
     $term_ids = array_map( 'intval', $term_ids );
     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
 }
 }}}

 Alternatively, for better debugging:

 {{{#!php
 <?php
 foreach ( (array) $taxonomies as $taxonomy ) {
     $term_ids = wp_get_object_terms( $object_id, $taxonomy, array(
 'fields' => 'ids' ) );
     if ( is_wp_error( $term_ids ) ) {
         // Log error but continue deletion process
         error_log( sprintf(
             'Error retrieving terms for taxonomy "%s" on object %d: %s',
             $taxonomy,
             $object_id,
             $term_ids->get_error_message()
         ) );
         continue;
     }
     $term_ids = array_map( 'intval', $term_ids );
     wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
 }
 }}}

 == Impact
 This is a **defensive programming issue**. While the underlying cause
 (taxonomy not registered) may vary by installation, WordPress core should
 handle `WP_Error` returns from its own functions gracefully rather than
 causing fatal errors. This affects PHP 8.0+ users and will become more
 prevalent as PHP 7.x reaches end-of-life.

 == Additional Context
 This issue was discovered when attempting to delete media library items on
 a WordPress 6.9 installation running PHP 8.3. The error occurred because
 `post_tag` taxonomy was not registered during the AJAX deletion request,
 causing `wp_get_object_terms()` to return a `WP_Error` with the message
 "Invalid taxonomy".

 While the specific trigger may be environment-dependent, the lack of error
 handling is a core issue that should be addressed for PHP 8.x
 compatibility and general code robustness.

--

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/64406#comment:1>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list