Every WooCommerce plugin or custom theme needs to read product data — prices, stock, attributes, shipping class, variations, images. WooCommerce exposes this data through the WC_Product class and its subclasses (WC_Product_Simple, WC_Product_Variable, WC_Product_Grouped, WC_Product_External, WC_Product_Variation). Together they offer 60+ getter methods. This is the complete, organized reference of the WooCommerce product functions you’ll actually use in real plugin and theme code.
The right way to access product data has changed across WooCommerce versions. Older code accessed properties directly ($product->price) — that pattern is deprecated and breaks with HPOS. Modern WooCommerce uses CRUD-style getters and setters ($product->get_price(), $product->set_price()) which work consistently across post-meta and HPOS storage. Every function in this reference uses the current, HPOS-safe API.
Quick navigation: the sections below group functions by purpose — getting a product object, identity/status, pricing, stock, attributes (with the slug-vs-name gotcha covered), shipping class, purchase quantities (with cart-aware logic), variations, grouped products, images, dimensions, downloads, reviews, and add-to-cart UI helpers. Each group includes working code patterns and the common mistakes that break in production.
WooCommerce product functions: quick reference
If you are evaluating WooCommerce product functions for your next project, you are weighing real trade-offs between cost, complexity, ownership, and time-to-launch. The right WooCommerce product functions decision depends on a handful of variables — team capacity, scope clarity, and how much ongoing maintenance you can absorb. The summary below is the 60-second version; the rest of this guide unpacks the nuance.
- WooCommerce product functions pricing typically ranges based on scope clarity, integration count, and ongoing support requirements.
- WooCommerce product functions timelines vary from days (small scope) to months (enterprise scope) depending on complexity.
- The biggest variable in WooCommerce product functions is requirements clarity at the brief stage — vague briefs produce vague quotes.
- Vendor selection for WooCommerce product functions matters more than tool selection — the right team beats the right stack.
- WooCommerce product functions ROI is positive when scope is bounded, deliverables are specified, and success criteria are measurable.
For complementary perspectives on WooCommerce product functions, the official WC_Product class reference and WC_Product_Variation class reference resources cover adjacent angles worth reviewing alongside this guide. They focus on the underlying technology and standards — this post focuses on the WooCommerce product functions decision specifically.
When you revisit your WooCommerce product functions approach in 12 to 24 months, three signals usually indicate a refresh is justified. First, the original brief no longer matches business reality — product, audience, or operational scope has shifted. Second, the underlying technology has moved forward enough that the WooCommerce product functions decision made under previous constraints would be different today. Third, ongoing maintenance overhead has crept up beyond what was forecast at launch. None of these are emergencies on their own; together they signal it is time to revisit fundamentals rather than patch around them.
How to get a WooCommerce product object
Every other WooCommerce product function starts with having a WC_Product object. The right way to get one is wc_get_product() with a guard:
// Get a WooCommerce product object by ID. The recommended way —
// returns false if the product doesn't exist or the ID is wrong.
$product = wc_get_product( $product_id );
if ( ! $product instanceof WC_Product ) {
// Product doesn't exist, was deleted, or ID was invalid.
return;
}
// Now you have full access to the WC_Product API
echo $product->get_name();
echo $product->get_price();
// Get the product object from the global $product (inside the loop)
global $product;
if ( $product instanceof WC_Product ) {
// Safe to call $product methods
}
// Get product from a post object
$product = wc_get_product( $post->ID );
// Get product type-specific class
// (e.g., WC_Product_Variable, WC_Product_Grouped, WC_Product_Variation)
$product_type = $product->get_type(); // 'simple', 'variable', 'grouped', 'external', 'variation'Always check the instance:
wc_get_product()returnsfalseif the ID doesn’t exist, the product was deleted, or the post type isn’t a product. Calling getter methods onfalsethrows a fatal error. The$product instanceof WC_Productguard prevents this and also tells static analyzers (PHPStan, Psalm) the variable type.
Product identity + status functions
The basics — how WooCommerce identifies and classifies each product.
| Function | Returns | Notes |
|---|---|---|
$product->get_id() | int | Product post ID |
$product->get_name() | string | Display name (post_title) |
$product->get_slug() | string | URL-safe slug (post_name) |
$product->get_title() | string | Alias for get_name() |
$product->get_type() | string | “simple”, “variable”, “grouped”, “external”, “variation” |
$product->get_status() | string | “publish”, “draft”, “pending”, “private” |
$product->get_featured() | bool | Is the product flagged as featured? |
$product->get_catalog_visibility() | string | “visible”, “catalog”, “search”, “hidden” |
$product->get_parent_id() | int | Parent product ID (for variations + grouped children) |
$product->get_menu_order() | int | Display order in archives |
$product->get_sku() | string | Stock-keeping unit — unique product identifier |
$product->get_date_created() | WC_DateTime | Creation timestamp |
$product->get_date_modified() | WC_DateTime | Last-modified timestamp |
$product->get_total_sales() | int | Cumulative units sold |
$product->get_formatted_name() | string | Name with ID + SKU appended — useful in admin lists |
WooCommerce product pricing functions
Pricing has the most getters because there are multiple price contexts: raw values, tax-included, tax-excluded, currency-formatted HTML. The complete pricing toolkit:
// Basic price getters — return raw values (strings, since prices in WC
// are stored as strings to avoid floating-point precision issues).
$active_price = $product->get_price(); // current price (sale if active, else regular)
$regular_price = $product->get_regular_price(); // always the regular price
$sale_price = $product->get_sale_price(); // sale price (empty if not on sale)
// Sale date range
$sale_from = $product->get_date_on_sale_from(); // WC_DateTime or null
$sale_to = $product->get_date_on_sale_to(); // WC_DateTime or null
// Tax-aware price helpers — return values adjusted for tax settings.
$incl_tax = wc_get_price_including_tax( $product ); // adds tax to price
$excl_tax = wc_get_price_excluding_tax( $product ); // strips tax from price
$display = wc_get_price_to_display( $product ); // respects the WC display setting
// Format any price value as HTML using the store's currency formatting.
echo wc_price( $display ); // <span class="woocommerce-Price-amount...">
// The pre-rendered price HTML — handles sale dashes, variation ranges, etc.
echo $product->get_price_html(); // recommended for theme display
// Get the price suffix (e.g., "ex. VAT") configured in WC settings.
echo $product->get_price_suffix();Prices are strings, not floats: WooCommerce stores prices as strings to avoid floating-point precision bugs in monetary calculations. When doing math, use
floatval()orwc_format_decimal(). For display, neverecho $priceraw — always wrap inwc_price( $price )for currency-formatted HTML.
Stock + inventory functions
Stock management functions — for reading current state. To update stock programmatically, use wc_update_product_stock() instead of direct setters (it fires the right hooks):
// Stock management — every stock-related getter.
$product->get_manage_stock(); // bool — is stock management enabled?
$product->get_stock_quantity(); // int|null — null means stock not tracked
$product->get_stock_status(); // 'instock' | 'outofstock' | 'onbackorder'
$product->get_backorders(); // 'no' | 'notify' | 'yes'
$product->get_low_stock_amount(); // int|string — threshold for low stock notifications
$product->get_sold_individually(); // bool — one per order only
// Convenience checks
$product->is_in_stock(); // boolean
$product->is_on_backorder( $qty ); // boolean — true if $qty would trigger backorder
$product->is_purchasable(); // boolean — combines stock + price + status
// Reduce / increase stock programmatically (use wc_update_product_stock instead)
wc_update_product_stock( $product, $new_quantity, 'set' ); // 'set', 'increase', 'decrease'Product attributes functions
Attributes are the most-confusing area of WooCommerce product functions because they handle BOTH custom text attributes (typed per-product) AND taxonomy-based global attributes (pa_color, pa_size). The relevant getters:
// Get a single attribute as a string.
// WC's get_attribute() returns the VALUE — display-friendly for visible attributes.
// For taxonomy-based attributes (pa_color, pa_size, etc.) it returns
// comma-separated term names, not slugs.
$color_value = $product->get_attribute( 'pa_color' ); // e.g., "Red, Blue"
// Get all attributes as an array of WC_Product_Attribute objects.
$attributes = $product->get_attributes();
foreach ( $attributes as $key => $attribute ) {
// $attribute is WC_Product_Attribute
echo $attribute->get_name(); // 'pa_color' or 'Color' (for custom attributes)
echo $attribute->is_taxonomy(); // bool
echo $attribute->get_visible(); // bool — shown on product page?
echo $attribute->get_variation(); // bool — used for variations?
if ( $attribute->is_taxonomy() ) {
$terms = $attribute->get_terms(); // array of WP_Term objects
foreach ( $terms as $term ) {
echo $term->slug . ': ' . $term->name;
}
} else {
echo $attribute->get_options(); // array of raw option strings
}
}
// Get default attribute values for a variable product
$defaults = $product->get_default_attributes(); // array — keyed by attribute nameget_attribute() returns NAMES, not slugs:
$product->get_attribute( 'pa_color' )returns the comma-separated display names (“Red, Blue”) for taxonomy attributes — convenient for display. If you need slugs (for filtering, URL building, or programmatic logic), use$product->get_attributes(), find the WC_Product_Attribute, then iterate$attribute->get_terms()for term objects.
Variation-specific functions (wc_product_variation get_attribute and friends)
For variable products, each variation is a separate WC_Product_Variation object with its own attribute values. The variation API differs subtly from the parent variable product:
// Variation-specific patterns. WC_Product_Variation extends WC_Product
// with a few extra methods for variation-specific data.
if ( $product->is_type( 'variation' ) ) {
// The parent variable product's ID
$parent_id = $product->get_parent_id();
// Get the variation's attribute values — keyed by 'attribute_pa_color' etc.
// Returns SLUGS, not display names, because variations store slugs internally.
$variation_attrs = $product->get_variation_attributes();
// e.g., array( 'attribute_pa_color' => 'red', 'attribute_pa_size' => 'large' )
// To get the human-readable name from a variation slug:
$term = get_term_by( 'slug', 'red', 'pa_color' );
echo $term->name; // "Red"
// OR use wc_attribute_label() for the attribute LABEL (not value)
echo wc_attribute_label( 'pa_color' ); // "Color"
}
// For a variable product, get all available variations
if ( $product->is_type( 'variable' ) ) {
$variations = $product->get_available_variations(); // array of variation data
$variation_ids = $product->get_children(); // array of variation IDs
}Variations store SLUGS, not names: A common source of bugs:
$variation->get_variation_attributes()returns an array where keys areattribute_{taxonomy}(e.g.,attribute_pa_color) and values are TERM SLUGS (e.g.,red). To display the human name “Red” instead of the slug “red”, look up the term viaget_term_by( 'slug', $slug, $taxonomy )and use$term->name.
Categories, tags, and shipping class functions
Taxonomy getters return IDs for the term-relationship lookups, slugs for shipping class. The shipping class case is the gotcha that catches most developers:
// Shipping class getters — common gotcha: get_shipping_class() returns
// the SLUG, not the human-readable name. To get the name, use the slug
// to fetch the term, or use the *_id() variant.
$shipping_class_slug = $product->get_shipping_class(); // e.g., 'heavy-items'
$shipping_class_id = $product->get_shipping_class_id(); // e.g., 42 (term ID)
// Get the human-readable shipping class name
if ( $shipping_class_slug ) {
$term = get_term_by( 'slug', $shipping_class_slug, 'product_shipping_class' );
echo $term ? $term->name : ''; // e.g., "Heavy Items"
}
// Alternative — get the term directly via ID (one fewer query in some cases)
if ( $shipping_class_id ) {
$term = get_term( $shipping_class_id, 'product_shipping_class' );
echo $term && ! is_wp_error( $term ) ? $term->name : '';
}| Function | Returns | Notes |
|---|---|---|
$product->get_category_ids() | int[] | Array of product_cat term IDs |
$product->get_tag_ids() | int[] | Array of product_tag term IDs |
$product->get_shipping_class() | string | Shipping class SLUG (not name!) |
$product->get_shipping_class_id() | int | Shipping class term ID |
For category/tag NAMES (not IDs), use the WP core get_the_terms( $product_id, 'product_cat' ) or wp_get_post_terms(). Both return arrays of WP_Term objects with name + slug + ID.
Purchase quantity functions (and how they interact with cart quantity)
Minimum and maximum purchase quantities have non-obvious interactions with stock, sold-individually flag, and what’s already in the cart. The full pattern:
// Min and max purchase quantity. These methods respect:
// - WC settings (default min 1, max -1 means no limit)
// - sold_individually flag (forces max to 1)
// - stock_quantity (caps max at remaining stock when stock tracking is on)
// - backorders setting
$min_qty = $product->get_min_purchase_quantity(); // int — usually 1
$max_qty = $product->get_max_purchase_quantity(); // int — -1 means unlimited
// Cart-aware check — accounts for what's already in the cart for this product
// (so the same item can't be added past its max via repeated adds)
$cart_qty = WC()->cart ? WC()->cart->get_cart_item_quantities() : array();
$already_in_cart = isset( $cart_qty[ $product->get_id() ] ) ? $cart_qty[ $product->get_id() ] : 0;
$remaining_allowed = $max_qty === -1 ? PHP_INT_MAX : max( 0, $max_qty - $already_in_cart );
if ( $remaining_allowed === 0 ) {
// Max already in cart; show "max reached" message instead of add-to-cart
}
// Override max for specific products via the filter
add_filter( 'woocommerce_quantity_input_max', function ( $max, $product ) {
if ( $product->get_id() === 42 ) {
return 5; // hardcoded max for product 42
}
return $max;
}, 10, 2 );sold_individually overrides everything: When
get_sold_individually()is true, the effective max purchase quantity is always 1, regardless ofget_max_purchase_quantity(). Common pattern: digital products + booking products are sold individually. Don’t hardcode max checks; respect the sold_individually flag.
Grouped product functions (get_children)
Grouped products are a container for other products. get_children() returns the IDs of the products inside the group:
// Grouped products group other products together. get_children() returns
// the array of CHILD PRODUCT IDs that are part of the group.
if ( $product->is_type( 'grouped' ) ) {
$child_ids = $product->get_children(); // array of product IDs
// Loop to display each child
foreach ( $child_ids as $child_id ) {
$child = wc_get_product( $child_id );
if ( ! $child instanceof WC_Product ) continue;
echo $child->get_name();
echo $child->get_price_html();
echo $child->add_to_cart_url();
}
}
// Also useful: detecting grouped product membership from a child's side
$parent_id = $product->get_parent_id();
if ( $parent_id ) {
$parent = wc_get_product( $parent_id );
if ( $parent && $parent->is_type( 'grouped' ) ) {
// This product is a child of a grouped product
}
}Images and gallery functions
Product imagery — featured image, gallery, custom sizes:
// Product images — featured image + gallery.
echo $product->get_image( 'woocommerce_thumbnail' ); // featured image HTML
echo $product->get_image_id(); // attachment ID of featured
// Gallery images
$gallery_ids = $product->get_gallery_image_ids(); // array of attachment IDs
foreach ( $gallery_ids as $attachment_id ) {
echo wp_get_attachment_image( $attachment_id, 'woocommerce_single' );
}
// Custom image size (theme-defined image sizes also work)
echo $product->get_image( array( 600, 600 ), array( 'class' => 'custom-img' ) );Dimensions and weight functions
Physical product properties — used by shipping calculations and display:
| Function | Returns | Notes |
|---|---|---|
$product->get_weight() | string | Weight in store’s configured unit |
$product->get_length() | string | Length in configured unit |
$product->get_width() | string | Width |
$product->get_height() | string | Height |
$product->get_dimensions() | string|array | Formatted “L x W x H” string by default; pass false for raw array |
$product->has_dimensions() | bool | Does the product have any dimensions set? |
$product->has_weight() | bool | Does it have a weight? |
Dimension getters return strings — use floatval() before doing math. For unit-aware display, use wc_format_dimensions() or wc_format_weight().
Downloadable product functions
For downloadable products (digital goods), WooCommerce stores file metadata and access controls:
| Function | Returns | Notes |
|---|---|---|
$product->get_downloadable() | bool | Is the product downloadable? |
$product->get_downloads() | array | Array of WC_Product_Download objects |
$product->get_download_limit() | int | Max downloads per customer (-1 = unlimited) |
$product->get_download_expiry() | int | Days until download link expires (-1 = never) |
$product->get_file( $download_id ) | WC_Product_Download | Single file by ID |
$product->get_file_download_path( $download_id ) | string | Server file path |
Reviews and ratings functions
Customer feedback aggregates — useful for product display, sorting, and recommendation logic:
| Function | Returns | Notes |
|---|---|---|
$product->get_reviews_allowed() | bool | Are reviews enabled for this product? |
$product->get_average_rating() | string | Average rating (“4.5”) or “0” if no reviews |
$product->get_review_count() | int | Total review count |
$product->get_rating_counts() | int[] | Count by star rating: array( 5 => 12, 4 => 3, … ) |
$product->get_rating_count( $value ) | int | Count for one star value (or total if value is null) |
$product->get_rating_html() | string | Pre-rendered star rating HTML |
Upsells, cross-sells, and related products
Product relationships used by WooCommerce’s recommendation engine:
| Function | Returns | Notes |
|---|---|---|
$product->get_upsell_ids() | int[] | Manually-selected upsell product IDs |
$product->get_cross_sell_ids() | int[] | Manually-selected cross-sell product IDs |
wc_get_related_products( $product_id, $limit ) | int[] | Auto-detected related products (same category/tag) |
Description and content functions
Product copy — used in templates and emails:
| Function | Returns | Notes |
|---|---|---|
$product->get_description() | string | Long description (post_content) |
$product->get_short_description() | string | Short description (post_excerpt) |
$product->get_purchase_note() | string | Note shown after purchase + in order emails |
Description content may contain HTML, shortcodes, and embedded blocks. For display, run through do_shortcode() and wp_kses_post(). For plain-text contexts (emails, exports), use wp_strip_all_tags().
Add to cart UI helper functions
For custom product loops or AJAX-driven UI, you need the same URL and button-text helpers that WooCommerce’s default loop uses:
// Add to cart URL + button text helpers — useful for custom loop layouts.
echo esc_url( $product->add_to_cart_url() ); // URL with ?add-to-cart=ID param
echo esc_html( $product->add_to_cart_text() ); // "Add to cart" / "Read more" / etc.
echo esc_html( $product->single_add_to_cart_text() ); // Button text for single product page
echo esc_html( $product->add_to_cart_description() ); // Aria-label / description text
// AJAX add to cart class (used by themes for the loop add-to-cart button)
echo esc_attr( implode( ' ', array(
'button',
'product_type_' . $product->get_type(),
$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
$product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : '',
) ) );Tax-aware pricing helpers
Beyond the basic price getters, WooCommerce ships standalone pricing functions that respect the store’s tax configuration:
| Function | Purpose |
|---|---|
wc_get_price_including_tax( $product, $args ) | Add tax to the product’s price |
wc_get_price_excluding_tax( $product, $args ) | Strip tax from the product’s price |
wc_get_price_to_display( $product, $args ) | Respect store’s “Display prices including/excluding tax” setting |
wc_price( $value ) | Format any numeric value as currency HTML |
wc_format_decimal( $value, $precision ) | Format a decimal with WC’s decimal separator settings |
HPOS-aware patterns for WooCommerce product functions
WooCommerce 8.0+ introduced High-Performance Order Storage (HPOS), and similar architectural improvements are spreading to products in later versions. For product functions specifically:
- Use CRUD getters/setters, NEVER direct property access —
$product->get_price()✓,$product->price✗ (deprecated since WC 3.0; breaks on HPOS-affected configurations) - Use
wc_get_product(), NEVERget_post()for product retrieval — wc_get_product returns the correct WC_Product subclass; get_post returns a raw WP_Post that misses WC methods - Use
wc_update_product_stock(), NEVER rawupdate_post_meta()for stock updates — the helper fires the right hooks and triggers stock notifications - For order data inside product callbacks, use HPOS-safe order APIs (
wc_get_orders(),$order->get_meta()) — never raw post queries against shop_order - Save() must be called after setters —
$product->set_price( 99 )changes the in-memory object;$product->save()writes to the database
Common mistakes with WooCommerce product functions
Patterns that look correct but cause real bugs:
- Forgetting the
instanceof WC_Productguard — calling getters onfalsethrows a fatal error - Using
get_attribute()when you need slugs — returns display names, not slugs; useget_attributes()+ iterate WC_Product_Attribute objects - Confusing
get_shipping_class()with the class name — returns the SLUG; use the slug or _id() variant to look up the WP_Term for the name - Math on string prices — WC prices are strings; cast with
floatval()or usewc_format_decimal() - Direct property access (
$product->price) — deprecated since WC 3.0; use CRUD getters - Not calling
$product->save()after setters — setters mutate in-memory state only; save persists to DB - Querying products with
WP_Query— usewc_get_products()instead; it returns WC_Product objects and respects WC-specific filters - Stale product objects after stock changes — after
wc_update_product_stock(), re-fetch the product withwc_get_product( $id )to see updated stock
Basics — FAQs
How do I get a WooCommerce product object by ID?
Use wc_get_product( $product_id ). It returns a WC_Product object (or one of its subclasses like WC_Product_Variable) on success, or false if the product doesn’t exist or the ID is invalid. Always check the return value with $product instanceof WC_Product before calling getter methods — calling them on false throws a fatal error.
What's the difference between get_price(), get_regular_price(), and get_sale_price()?
get_regular_price() always returns the regular price (set in the product’s “Regular price” field). get_sale_price() returns the sale price (or empty string if not on sale). get_price() returns the ACTIVE price — sale price if a sale is currently active, otherwise regular price. For most display logic, use get_price(); for sale-comparison UI (“$50 was ~~$80~~”), use both get_regular_price() and get_sale_price() explicitly.
How do I check if a WooCommerce product is on sale?
$product->is_on_sale() returns a boolean. It accounts for the sale date range (only true if today is within the configured sale-from/sale-to dates) AND whether a sale price is set. To get the sale price for display: $product->get_sale_price() for the raw value, $product->get_price_html() for the pre-rendered “$80 $50″ markup.
Attributes + variations — FAQs
Why does $product->get_attribute() return names instead of slugs?
get_attribute() is a display-focused helper — it returns the comma-separated DISPLAY NAMES of taxonomy attribute terms (e.g., “Red, Blue”) because that’s what themes typically need to show. For slug-level data (URL building, filtering), use get_attributes() to get the full array of WC_Product_Attribute objects, then call $attribute->get_terms() to get WP_Term objects with both slug and name properties.
How do I get the human name from a variation attribute slug?
Variations store attribute SLUGS in get_variation_attributes() (e.g., attribute_pa_color => 'red'). To convert to the display name “Red”, use get_term_by( 'slug', $slug, $taxonomy ). For the attribute LABEL (“Color” vs “Size”), use wc_attribute_label( $taxonomy ) which respects WC’s attribute label settings.
How do I get all variations of a variable product?
For variation OBJECTS: $product->get_children() returns an array of variation IDs; loop with wc_get_product( $id ). For variation METADATA (used in JavaScript-driven variation pickers): $product->get_available_variations() returns an array of arrays with each variation’s attributes, price, image, stock, etc. The first is for backend iteration; the second is for frontend display.
Stock + cart — FAQs
How does get_max_purchase_quantity() interact with cart quantity?
get_max_purchase_quantity() returns the configured max (-1 = unlimited) without knowing what’s already in the cart. To compute “how many more can the customer add”, subtract the current cart quantity from the max: max( 0, $max - $already_in_cart ). Also respect get_sold_individually() — when true, the effective max is always 1 regardless of get_max_purchase_quantity().
What's the safe way to update product stock?
Use wc_update_product_stock( $product, $new_quantity, $operation ) where $operation is “set”, “increase”, or “decrease”. This helper fires the right hooks (woocommerce_product_set_stock, low-stock notifications, etc.) that direct update_post_meta() calls miss. After updating, re-fetch the product with wc_get_product( $id ) to see the new stock value (your existing $product variable is now stale).
How do I get the human-readable shipping class name (not the slug)?
Two steps. $product->get_shipping_class() returns the slug. Then get_term_by( 'slug', $slug, 'product_shipping_class' ) returns the WP_Term object — use $term->name for the display name. Alternative: $product->get_shipping_class_id() gives the term ID directly, which you can pass to get_term().
What is the most important factor in WooCommerce product functions?
The single most important factor in WooCommerce product functions is matching the project scope to the right delivery model. WooCommerce product functions done by the wrong team type can cost 3-5x more than necessary; WooCommerce product functions done by the right team is predictable, bounded, and produces measurable value. Run an honest scope discovery before committing to any WooCommerce product functions engagement, and insist on detailed deliverables in the SOW so both sides are aligned on what success looks like.

