diff --git src/wp-includes/widgets/class-wp-widget-custom-html.php src/wp-includes/widgets/class-wp-widget-custom-html.php
index 855c3c5895..758e08c3ba 100644
--- src/wp-includes/widgets/class-wp-widget-custom-html.php
+++ src/wp-includes/widgets/class-wp-widget-custom-html.php
@@ -85,11 +85,23 @@ class WP_Widget_Custom_HTML extends WP_Widget {
 	 *
 	 * @since 4.8.1
 	 *
+	 * @global WP_Post $post
 	 * @param array $args     Display arguments including 'before_title', 'after_title',
 	 *                        'before_widget', and 'after_widget'.
 	 * @param array $instance Settings for the current Custom HTML widget instance.
 	 */
 	public function widget( $args, $instance ) {
+		global $post;
+
+		// Override global $post so filters (and shortcodes) apply in a consistent context.
+		$original_post = $post;
+		if ( is_singular() ) {
+			// Make sure post is always the queried object on singular queries (not from another sub-query that failed to clean up the global $post).
+			$post = get_queried_object();
+		} else {
+			// Nullify the $post global during widget rendering to prevent shortcodes from running with the unexpected context on archive queries.
+			$post = null;
+		}
 
 		$instance = array_merge( $this->default_instance, $instance );
 
@@ -118,6 +130,9 @@ class WP_Widget_Custom_HTML extends WP_Widget {
 		 */
 		$content = apply_filters( 'widget_custom_html_content', $content, $instance, $this );
 
+		// Restore post global.
+		$post = $original_post;
+
 		// Inject the Text widget's container class name alongside this widget's class name for theme styling compatibility.
 		$args['before_widget'] = preg_replace( '/(?<=\sclass=["\'])/', 'widget_text ', $args['before_widget'] );
 
diff --git src/wp-includes/widgets/class-wp-widget-text.php src/wp-includes/widgets/class-wp-widget-text.php
index ffcfe0cd09..a6a0b44c23 100644
--- src/wp-includes/widgets/class-wp-widget-text.php
+++ src/wp-includes/widgets/class-wp-widget-text.php
@@ -221,10 +221,13 @@ class WP_Widget_Text extends WP_Widget {
 			remove_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority );
 		}
 
-		// Nullify the $post global during widget rendering to prevent shortcodes from running with the unexpected context.
-		$suspended_post = null;
-		if ( isset( $post ) ) {
-			$suspended_post = $post;
+		// Override global $post so filters (and shortcodes) apply in a consistent context.
+		$original_post = $post;
+		if ( is_singular() ) {
+			// Make sure post is always the queried object on singular queries (not from another sub-query that failed to clean up the global $post).
+			$post = get_queried_object();
+		} else {
+			// Nullify the $post global during widget rendering to prevent shortcodes from running with the unexpected context on archive queries.
 			$post = null;
 		}
 
@@ -278,9 +281,7 @@ class WP_Widget_Text extends WP_Widget {
 		}
 
 		// Restore post global.
-		if ( isset( $suspended_post ) ) {
-			$post = $suspended_post;
-		}
+		$post = $original_post;
 
 		// Undo suspension of legacy plugin-supplied shortcode handling.
 		if ( $should_suspend_legacy_shortcode_support ) {
