Skip to main content
FolksSpeakersPluginsThemesEventsSnippetsShippedCommunityResources
Login Join
Snippet · PHP

Easy Digital Downloads Product and Review Schema Shortcode

Shared by Ronald Huereca · May 3, 2026

3 views
Back to Snippets

This shortcode outputs Easy Digital Downloads product/review schema on custom pages, allowing you to show up on Google for Rich Snippets. This is useful if you don’t use the /downloads/ endpoint and have custom product pages.

Usage: `[edd_structured_data id=12345]`

 

<?php
*
 * Example Usage:
 * [edd_structured_data id="123"]
 */
add_shortcode(
	'edd_structured_data',
	function ( $atts ) {
		$atts = shortcode_atts( [
			'id' => 0,
		], $atts );

		$download_id = absint( $atts['id'] );
		if ( ! $download_id || ! class_exists( 'Easy_Digital_Downloads' ) ) {
			return '';
		}

		$edd = Easy_Digital_Downloads::instance();

		$current_post_id = get_the_ID();
		
		// Store the original global post to restore later.
		global $post;
		$original_post = $post;
		
		// Set the global post to the download post so edd-reviews can find the reviews.
		$post = get_post( $download_id );
		setup_postdata( $post );

		ob_start();
		$filter_callback = function ( $data, $download ) use ( $current_post_id ) {
			$data['url'] = get_permalink( $current_post_id );
			return $data;
		};

		add_filter( 'edd_generate_download_structured_data', $filter_callback, 10, 2 );

		// Generate the schema.
		$edd->structured_data->generate_download_data( $download_id );
		$edd->structured_data->output_structured_data();

		remove_filter( 'edd_generate_download_structured_data', $filter_callback, 10, 2 );

		// Restore the original global post.
		wp_reset_postdata();
		$post = $original_post;

		$data = ob_get_clean();

		// Remove the last occurrence of aggregateRating from JSON-LD to prevent duplicate AggregateRating warnings.
		// Extract JSON from script tag, decode, remove property, and re-encode.
		if ( preg_match( '/<script[^>]*type=["']application/ld+json["'][^>]*>(.*?)</script>/s', $data, $json_matches ) ) {
			$json_string = $json_matches[1];
			$json_data = json_decode( $json_string, true );
			
			if ( is_array( $json_data ) && ! empty( $json_data ) ) {
				// Remove aggregateRating from the last item in the array.
				$last_index = count( $json_data ) - 1;
				if ( isset( $json_data[ $last_index ]['aggregateRating'] ) ) {
					unset( $json_data[ $last_index ]['aggregateRating'] );
					// Re-encode the JSON and replace in the output.
					$new_json = wp_json_encode( $json_data );
					$data = str_replace( $json_string, $new_json, $data );
				}
			}
		}

		return $data;
	}
);