You are currently viewing How to integrate Custom Post Type in WooCommerce and update pricing

How to integrate Custom Post Type in WooCommerce and update pricing

WooCommerce is one of the best Online Shipping and open source systems in WordPress. WooCommerce is used for Online stores, Digital stores, Donation systems, Services, Consulting Websites, and much more. It is designed to be used for small and large scale online merchandising websites built with WordPress. It is also compatible with Yoast SEO by Automattic and you could launch SEO friendly WordPress website.

WooCommerce is a huge and flexible eCommerce system as well as offers ample extensions that are used to enhance the functionality of WooCommerce website.

Extensions developers of WooCommerce also have to give immense development hooks and flexibility so that they can develop any kind of extensions using WooCommerce. Agencies or developers can meet any of their client’s needs using WooCommerce.

Today, we’ll describe a little trick that is needed of many developers in which we’ll tell you how to register custom post type and then integrate it into WooCommerce.

Explore the full working Plugin here

Let’s Start with Registering a Post Type

In WordPress, if you doing some customization in Child Theme or a Plugin. You can write the below code at the top level either in the plugin’s root file or in functions.php in your child theme.

You can read more about registering custom post types on WordPress developers resources. Here we are going to register a custom post type “Books”

 * Register a custom post type called "book".
 * @see get_post_type_labels() for label keys.
function wpdocs_codex_book_init() {
    $labels = array(
        'name'                  => _x( 'Books', 'Post type general name', 'textdomain' ),
        'singular_name'         => _x( 'Book', 'Post type singular name', 'textdomain' ),
        'menu_name'             => _x( 'Books', 'Admin Menu text', 'textdomain' ),
        'name_admin_bar'        => _x( 'Book', 'Add New on Toolbar', 'textdomain' ),
        'add_new'               => __( 'Add New', 'textdomain' ),
        'add_new_item'          => __( 'Add New Book', 'textdomain' ),
        'new_item'              => __( 'New Book', 'textdomain' ),
        'edit_item'             => __( 'Edit Book', 'textdomain' ),
        'view_item'             => __( 'View Book', 'textdomain' ),
        'all_items'             => __( 'All Books', 'textdomain' ),
        'search_items'          => __( 'Search Books', 'textdomain' ),
        'parent_item_colon'     => __( 'Parent Books:', 'textdomain' ),
        'not_found'             => __( 'No books found.', 'textdomain' ),
        'not_found_in_trash'    => __( 'No books found in Trash.', 'textdomain' ),
        'featured_image'        => _x( 'Book Cover Image', 'Overrides the “Featured Image” phrase for this post type. Added in 4.3', 'textdomain' ),
        'set_featured_image'    => _x( 'Set cover image', 'Overrides the “Set featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
        'remove_featured_image' => _x( 'Remove cover image', 'Overrides the “Remove featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
        'use_featured_image'    => _x( 'Use as cover image', 'Overrides the “Use as featured image” phrase for this post type. Added in 4.3', 'textdomain' ),
        'archives'              => _x( 'Book archives', 'The post type archive label used in nav menus. Default “Post Archives”. Added in 4.4', 'textdomain' ),
        'insert_into_item'      => _x( 'Insert into book', 'Overrides the “Insert into post”/”Insert into page” phrase (used when inserting media into a post). Added in 4.4', 'textdomain' ),
        'uploaded_to_this_item' => _x( 'Uploaded to this book', 'Overrides the “Uploaded to this post”/”Uploaded to this page” phrase (used when viewing media attached to a post). Added in 4.4', 'textdomain' ),
        'filter_items_list'     => _x( 'Filter books list', 'Screen reader text for the filter links heading on the post type listing screen. Default “Filter posts list”/”Filter pages list”. Added in 4.4', 'textdomain' ),
        'items_list_navigation' => _x( 'Books list navigation', 'Screen reader text for the pagination heading on the post type listing screen. Default “Posts list navigation”/”Pages list navigation”. Added in 4.4', 'textdomain' ),
        'items_list'            => _x( 'Books list', 'Screen reader text for the items list heading on the post type listing screen. Default “Posts list”/”Pages list”. Added in 4.4', 'textdomain' ),
    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'book' ),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => null,
        'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
    register_post_type( 'book', $args );
add_action( 'init', 'wpdocs_codex_book_init' );

Integration with WooCommerce

Now You’ll have to create a new PHP OOP Class and extend it to WC_Product_Data_Store_CPT. Then implement it to WC_Object_Data_Store_Interface, WC_Product_Data_Store_Interface as these are the WooCommerce core interfaces. Here we create a file at the path /includes/classes/class-data-store-cpt.php

class My_Product_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Product_Data_Store_Interface {

     * Method to read a product from the database.
     * @param WC_Product
    public function read( &$product ) {

        if ( ! $product->get_id() || ! ( $post_object = get_post( $product->get_id() ) ) || 'product' !== $post_object->post_type ) {
            //throw new Exception( __( 'Invalid product.', 'woocommerce' ) );

        $id = $product->get_id();

        $product->set_props( array(
            'name'              => $post_object->post_title,
            'slug'              => $post_object->post_name,
            'date_created'      => 0 < $post_object->post_date_gmt ? wc_string_to_timestamp( $post_object->post_date_gmt ) : null,
            'date_modified'     => 0 < $post_object->post_modified_gmt ? wc_string_to_timestamp( $post_object->post_modified_gmt ) : null,
            'status'            => $post_object->post_status,
            'description'       => $post_object->post_content,
            'short_description' => $post_object->post_excerpt,
            'parent_id'         => $post_object->post_parent,
            'menu_order'        => $post_object->menu_order,
            'reviews_allowed'   => 'open' === $post_object->comment_status,
        ) );

        $this->read_attributes( $product );
        $this->read_downloads( $product );
        $this->read_visibility( $product );
        $this->read_product_data( $product );
        $this->read_extra_data( $product );
        $product->set_object_read( true );


Then call this class via filter hook as below

add_filter( 'woocommerce_data_stores', 'my_woocommerce_data_stores' );
function my_woocommerce_data_stores( $stores ) {

    require_once PLUGIN_PATH . '/includes/classes/class-data-store-cpt.php';
    $stores['product'] = 'MY_Product_Data_Store_CPT';

    return $stores;

Now we’ll have to set the price via filter so whenever the user adds an item to the cart. WooCommerce should use our price. Also, we can use this filter on card and checkout pages.

add_filter('woocommerce_product_get_price', 'my_woocommerce_product_get_price', 10, 2 );
function my_woocommerce_product_get_price( $price, $product ) {

    if ( get_post_type( $product->get_id() ) === 'book' ) {
        $price = get_post_meta( $product->get_id(), '_book_price', true );
    return $price;

We’ll create a URL so the user clicks on it to add an item to the cart like http://localhost/wordpress/?add-to-cart=244 will add the item to the cart.

Here is an example of how to create add to cart button on a book detail page.

<form action="<?php echo get_permalink(); ?>" method="post">
      <input name="add-to-cart" type="hidden" value="<?php the_ID(); ?>" />
      <input name="quantity" type="number" value="1" min="1"  />
      <input name="submit" type="submit" value="Add to cart" />


Here is what we have learned. Registering a new Custom Post Type in WordPress. Integrating the custom post type in WooCommerce using our price whenever a user adds an item to the cart. image source

This Post Has 5 Comments

  1. aliceevra

    I use woocomerce version 6.2.1

    I got this error : “Warning: array_key_exists() expects parameter 2 to be array, null given in class-wc-data-store.php on line 86 , Warning: array_key_exists() expects parameter 2 to be array, null given in woocommerce/includes/class-wc-data-store.php on line 91 ,Fatal error: Uncaught Exception: Données boutique non validein includes/class-wc-data-store.php:107

    1. admin

      Hi, to diagnose the issue, you’ll have to provide the code you’ve written so far.

  2. George Locke

    You have done a great job. I wondered around since many days to find this solution. Some closest solution I found on stackoverslow but that were not 100%. This finally helped me to finish my job. I would like to hire you for my WordPress work. Cheers.

    1. Adrian Miller

      You need to generate a link like <a rel="nofollow ugc" href="<?php the_permalink();?>/?add-to-cart=<?php the_ID(); ?>">Add to Cart</a> in a loop of product listing page. If you want to generate add to cart button then you’ll have to use the form tag.

Leave a Reply