When you pass an array through json_encode() on the PHP side and then parse it with JSON.parse() or receive it via jQuery’s $.ajax, you may find that json_decode() returns null — or the JavaScript side receives unexpected string values instead of integers. The root cause is almost always a type mismatch in the PHP array.
Problem: json_decode() returns null on a string that looks like valid JSON, and json_last_error() reports an encoding or syntax error — making the decoded data unusable.
Solution: The most common causes are a UTF-8 BOM at the start of the string, mixed quotation marks from incorrect escaping, or a non-UTF-8 encoding. Use json_last_error_msg() to identify the exact issue, then sanitise the input with mb_convert_encoding() and trim() before calling json_decode().
Use var_dump() to inspect the array before encoding it. If the IDs are stored as strings instead of integers, the dump will look like this:
array(2) { [0]=> string(3) "212" [1]=> string(3) "211" }
But it should look like this:
array(2) { [0]=> int(212) [1]=> int(211) }
This problem often appears when you build a post-ID array using 'fields' => 'ids' combined with string concatenation (.=). The problematic pattern looks like this:
<?php
$args = [
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'fields' => 'ids',
'no_found_rows' => true,
];
$custom_post_type = new WP_Query( $args );
if ( $custom_post_type->have_posts() ) {
$custom_post_type_ids = [];
while ( $custom_post_type->have_posts() ) {
$custom_post_type->the_post();
$custom_post_type_ids[] .= $post; // .= coerces $post to string
}
wp_reset_postdata();
}
The correct fix is to use 'fields' => 'id=>parent' together with wp_list_pluck(), which preserves integer types and avoids the manual loop entirely:
<?php
$args = [
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'fields' => 'id=>parent',
'no_found_rows' => true,
];
$custom_post_type = new WP_Query( $args );
if ( $custom_post_type->have_posts() ) {
$custom_post_type_ids = wp_list_pluck( $custom_post_type->posts, 'ID' );
// $custom_post_type_ids is now an array of integers — safe to json_encode()
}
You could also cast each value with (int), but wp_list_pluck() is the cleaner, idiomatic WordPress solution.
NOTE: If json_decode() still returns null after fixing the types, check for encoding issues — any non-UTF-8 character in a string value will cause the entire JSON payload to be invalid. Run the output through json_last_error_msg() to get a specific diagnostic.