# Product Structured Data Without WooCommerce

> Outputs Product JSON-LD with price, currency, SKU, brand and availability for a catalog post type, so products shown without a shop can still get rich results.

- Type: PHP
- Runs: Frontend only
- Category: [SEO](https://wpide.com/library/category/seo/)
- Tags: schema, products, json-ld
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/seo-product-schema-no-woo/

## Code

```php
// Post type, currency and the custom fields holding product details.
$wpide_product_schema = array(
    'post_type'    => 'catalog_item',
    'currency'     => 'USD',
    'price'        => 'price',
    'sku'          => 'sku',
    'brand'        => 'brand',
    'availability' => 'availability', // in_stock, out_of_stock or preorder.
);

add_action( 'wp_head', function () use ( $wpide_product_schema ) {
    if ( ! is_singular( $wpide_product_schema['post_type'] ) ) {
        return;
    }

    $post = get_queried_object();

    if ( ! $post instanceof WP_Post ) {
        return;
    }

    $meta = function ( $field ) use ( $post, $wpide_product_schema ) {
        return trim( (string) get_post_meta( $post->ID, $wpide_product_schema[ $field ], true ) );
    };

    $data = array(
        '@context'    => 'https://schema.org',
        '@type'       => 'Product',
        'name'        => wp_strip_all_tags( get_the_title( $post ) ),
        'description' => wp_strip_all_tags( get_the_excerpt( $post ) ),
        'url'         => get_permalink( $post ),
        'image'       => get_the_post_thumbnail_url( $post, 'full' ),
        'sku'         => $meta( 'sku' ),
    );

    if ( $meta( 'brand' ) ) {
        $data['brand'] = array( '@type' => 'Brand', 'name' => $meta( 'brand' ) );
    }

    if ( is_numeric( $meta( 'price' ) ) ) {
        $map = array( 'out_of_stock' => 'OutOfStock', 'preorder' => 'PreOrder' );

        $data['offers'] = array(
            '@type'         => 'Offer',
            'price'         => (string) ( 0 + $meta( 'price' ) ),
            'priceCurrency' => $wpide_product_schema['currency'],
            'availability'  => 'https://schema.org/' . ( $map[ $meta( 'availability' ) ] ?? 'InStock' ),
            'url'           => get_permalink( $post ),
        );
    }

    echo '<script type="application/ld+json">' . wp_json_encode( array_filter( $data ), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG ) . "</script>\n";
} );
```

## Notes

Set the post type and the custom field names that hold each value. Skip it on WooCommerce products, which have their own schema.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Product Structured Data Without WooCommerce" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
