a related-content feature needs two separate checks: where the block is allowed to appear, and which records it is allowed to link to.
Why it happens
WordPress is_single() already supports custom post types as well as posts. Use is_singular() with a post-type list when you want an explicit allowlist; it also supports pages and attachments when those types are requested.
if ( is_singular( array( 'post', 'game' ) ) ) {
// Render related content.
}
This controls the current page. It does not control the publication status of the related items returned by a separate query.
Use two layers of filtering
- Limit the display context. Use
is_singular()with an explicit list of supported post types. - Limit related targets. Require the related-item query to return only published records.
- Generate links normally. Use WordPress permalink functions after the record has passed the status check.
-
Test every supported post type. Check a normal post and each custom post type separately.
For a direct database query, the important condition is equivalent to:
AND posts.post_status = 'publish'
When using WP_Query, express the same rule with post_status => 'publish'.
Why both checks matter
The singular-page check answers, “Should this block appear here?” The status filter answers, “Is this related destination public?” They solve different problems.
A feature can correctly appear on a custom post type and still expose an unwanted draft link if the related query does not filter by status. The reverse is also possible: the query may return only published records, but the block may never appear because the page condition is too narrow.
Common mistakes
- Cause: an overly broad display condition. Fix: use an explicit post-type allowlist rather than assuming
is_single()excludes custom types. -
Cause: relying on the current page status to protect related results. Fix: filter the related query itself to
publish. -
Cause: rendering stored HTML without inspecting its links. Fix: validate or regenerate saved related-content markup separately.
Exclude the current record and escape output
A related-content query should also exclude the current post, limit its result count, and specify the intended destination post types. Use esc_url() for the permalink and esc_html() for the link label. Test as a logged-out visitor so editor permissions do not conceal a public-status mistake.
Make the display rule explicit, then independently enforce public status in the related-item query. The next action is to test the feature on one standard post, one custom post, and one draft related record.
Reference: WordPress is_single reference.
