The Sample object
Product Sample for WooCommerce uses a Sample
object class which extends the WooCommerce WC_Data
class in the same way that the WC_Product
class does. This way, every property and method can be inherited and, eventually, adjusted to describe the sample properties, relative to the regular product it relates to.
The main difference with a regular product is that a sample is not stored as a separate row in the wp_posts
table. Instead, the information about the product sample is a set of metadata stored in the wp_postmeta
table with the same ID as the regular product. For this reason, from the perspective of the interaction with the database, the Sample
class doesn’t use a WC_Data_Store
class. It rather defines its own read
, save
, update
, or delete
methods that take care of the retrieval, update and deletion of the sample-related metadata from the wp_postmeta
table.
Still, the Sample
class is designed to closely replicate the same properties and methods of the WC_Product
class. This allows developers to extend the plugin using the knowledge they already have about the WC_Product
class.
For example, consider the following code snippet:
global $product;
echo $product->get_price();
// output: 10
Similarly, the following code snippet does the same thing but with the sample price instead:
global $product;
$sample = new Barn2\Plugin\WC_Product_Sample\Sample( $product );
echo $sample->get_price();
// output: 1
(Note the top-level namespace will change to Kestrel
in a future release, we will mirror this class for backwards compatibility, though, or announce a major change.)
In this code snippet, you can see that a sample object can be instantiated from the $product
object it refers to. This can be done by passing either the $product
object itself or its ID (although the former method, when viable, is preferred as it prevents an unnecessary call to the wc_get_product
function). Then, every property and method can be accessed the same way developers are already used to with the $product
object. The only difference is that the sample object will be returning the product sample properties instead of the regular product ones (when they are different, of course).
Whether the $sample
object will return the same result the $product
object does is just a matter of how the sample is configured. For example, if a sample is set to come from the same stock of the regular product, then all the inventory properties and methods (stock quantity, stock status, weight and dimensions) are going to return the exact same values the regular product does (and no additional, unnecessary data will be stored in the database).
The product property
Every sample can be instantiated from the product object it refers to. Because of the tight connection between a sample and the regular product it represents, a reference of the regular product is stored as a property of the sample object so that it can always be referred to when needed. This way, even for those properties or methods that are not replicated in the Sample class design, developers can always refer to the connected product and use its properties and methods instead.
Let’s consider the following example. A store owner wants to disable the possibility to order samples of all the products that are currently on sale. This can be easily done with the following code snippet:
add_filter( 'wsa_sample_should_add_button', function( $is_button_visible, $sample ) {
$product = $sample->get_product();
return $is_button_visible && ! $product->is_on_sale();
}, 10, 2 );
It is important to notice that, in the case of product variations, the product
property of a sample refers to the variation. If it is necessary to reference the variable product that variation is a child of, it will be possible to use the parent_product
property instead, which is going to be instantiated only if the current product is a variation.
Sample objects in actions and filters
Similar to what happens with properties and methods, the Sample
class replicates also many of the action and filter hooks associated with a WC_Product
class. For example, when retrieving a sample property, the value can be filtered using the wsa_sample_get_{$prop}
filter hook the exact same way one can use the woocommerce_product_get_{$prop}
filter hook for the same purpose. Let’s consider the following code snippet:
add_filter( 'wsa_sample_get_price', function( $price, $sample ) {
if ( ! $sample->is_virtual() ) {
$price += 2;
}
return $price;
}, 10, 2 );
The fragment above increases the price of samples of non-virtual products by 2 (e.g. $5 becomes $7). As you can see, the $sample
object has the same is_virtual()
conditional method a regular $product
object does and we don’t need to refer to the connected product object.
Filters
wsa_sample_add_to_cart_description
Filter the description of the add to cart button. This is used as the aria-label
attribute of the link element.
add_filter( 'wsa_sample_add_to_cart_description', 'my_wsa_sample_add_to_cart_description', 10, 2 );
function my_wsa_sample_add_to_cart_description( $description, $sample ) {
// your code here...
return $description;
}
wsa_sample_add_to_cart_text
Filter the text used for the sample button on the shop and product archive pages. If you want to customize the button used on single product pages, you have to use the wsa_sample_single_add_to_cart_text
filter hook instead.
add_filter( 'wsa_sample_add_to_cart_text', 'my_wsa_sample_add_to_cart_text', 10, 2 );
function my_wsa_sample_add_to_cart_text( $button_text, $sample ) {
if ( 0 === $sample->get_price() ) {
$button_text = __( 'Get a free sample!', 'my-text-domain' );
}
return $button_text;
}
wsa_sample_add_to_cart_url
Filter the URL of the product associated with the current sample object
add_filter( 'wsa_sample_add_to_cart_url', 'my_wsa_sample_add_to_cart_url', 10, 2 );
function my_wsa_sample_add_to_cart_url( $permalink, $sample ) {
// your code here...
return $permalink;
}
wsa_sample_backorders_allowed
Filter the condition determining whether backorders are allowed or not
add_filter( 'wsa_sample_backorders_allowed', 'my_wsa_sample_backorders_allowed', 10, 2 );
function my_wsa_sample_backorders_allowed( $backorders_allowed, $sample ) {
// your code here...
return $backorders_allowed;
}
wsa_sample_backorders_require_notification
Filter the condition determining whether backorders require notifications or not
add_filter( 'wsa_sample_backorders_require_notification', 'my_wsa_sample_backorders_require_notification', 10, 2 );
function my_wsa_sample_backorders_require_notification( $require_notification, $sample ) {
// your code here...
return $require_notification;
}
wsa_sample_downloadable_file_permission
Filter the downloadable file permission, passing the WC_Customer_Download
object, the Sample
object, the WC_Order
object, the quantity and the WC_Order_Item
object that corresponds to the sample in the order.
add_filter( 'wsa_sample_downloadable_file_permission', 'my_wsa_sample_downloadable_file_permission', 10, 5 );
function my_wsa_sample_downloadable_file_permission( $download, $sample, $order, $qty, $item ) {
// your code here...
return $download;
}
wsa_sample_empty_price_html
Filter the output of an empty price
add_filter( 'wsa_sample_empty_price_html', 'my_wsa_sample_empty_price_html', 10, 2 );
function my_wsa_sample_empty_price_html( $price, $sample ) {
// your code here...
return $price;
}
wsa_sample_file
Filter the file corresponding to a download ID
add_filter( 'wsa_sample_file', 'my_wsa_sample_file', 10, 3 );
function my_wsa_sample_file( $file, $sample, $download_id ) {
// your code here...
return $file;
}
wsa_sample_file_download_path
Filter the file download path
add_filter( 'wsa_sample_file_download_path', 'my_wsa_sample_file_download_path', 10, 3 );
function my_wsa_sample_file_download_path( $file_path, $sample, $download_id ) {
// your code here...
return $file_path;
}
wsa_sample_get_{$prop}
Filter the value of a sample property. The variable portion of the hook can be replaced with any of the internal properties of the product sample class: status
, price
, tax_status
, tax_class
, use_product_stock
, stock_status
, manage_stock
, stock
, backorders
, low_stock_amount
, weight
, length
, width
, height
, shipping_class_id
, downloads
, download_limit
, download_expiry
.
add_filter( 'wsa_sample_get_price', 'my_wsa_sample_get_price', 10, 2 );
function my_wsa_sample_get_price( $price, $sample ) {
// your code here...
return $price;
}
wsa_sample_get_availability
Filter the availability of the current sample
add_filter( 'wsa_sample_get_availability', 'my_wsa_sample_get_availability', 10, 2 );
function my_wsa_sample_get_availability( $availability, $sample ) {
// your code here...
return $availability;
}
wsa_sample_get_availability_class
Filter the HTML class of the availability element
add_filter( 'wsa_sample_get_availability_class', 'my_wsa_sample_get_availability_class', 10, 2 );
function my_wsa_sample_get_availability_class( $class, $sample ) {
// your code here...
return $class;
}
wsa_sample_get_availability_text
Filter the availability label of the current sample
add_filter( 'wsa_sample_get_availability_text', 'my_wsa_sample_get_availability_text', 10, 2 );
function my_wsa_sample_get_availability_text( $availability, $sample ) {
// your code here...
return $availability;
}
wsa_sample_get_dimensions
Filter the dimensions of the product sample
add_filter( 'wsa_sample_get_dimensions', 'my_wsa_sample_get_dimensions', 10, 2 );
function my_wsa_sample_get_dimensions( $dimensions, $sample ) {
// your code here...
return $dimensions;
}
wsa_sample_get_image
Filter the markup of the image attached to the product sample
add_filter( 'wsa_sample_get_image', 'my_wsa_sample_get_image', 10, 4 );
function my_wsa_sample_get_image( $image, $sample, $size, $placeholder ) {
// your code here...
return $image;
}
wsa_sample_get_price_html
Filter the price HTML markup of the current sample object
add_filter( 'wsa_sample_get_price_html', 'my_wsa_sample_get_price_html', 10, 2 );
function my_wsa_sample_get_price_html( $price, $sample ) {
// your code here...
return $price;
}
wsa_sample_get_price_suffix
Filter the price suffix of the current sample
add_filter( 'wsa_sample_get_price_suffix', 'my_wsa_sample_get_price_suffix', 10, 4 );
function my_wsa_sample_get_price_suffix( $suffix, $sample, $price, $qty ) {
// your code here...
return $suffix;
}
wsa_sample_is_in_stock
Filter the stock status
add_filter( 'wsa_sample_is_in_stock', 'my_wsa_sample_is_in_stock', 10, 2 );
function my_wsa_sample_is_in_stock( $is_in_stock, $sample ) {
// your code here...
return $is_in_stock;
}
wsa_sample_is_taxable
Filter whether the sample is taxable or not
add_filter( 'wsa_sample_is_taxable', 'my_wsa_sample_is_taxable', 10, 2 );
function my_wsa_sample_is_taxable( $is_taxable, $sample ) {
// your code here...
return $is_taxable;
}
wsa_sample_loop_add_to_cart_args
Filter the arguments passed to the loop add to cart button
add_filter( 'wsa_sample_loop_add_to_cart_args', 'my_wsa_sample_loop_add_to_cart_args', 10, 2 );
function my_wsa_sample_loop_add_to_cart_args( $args, $sample ) {
// your code here...
return $args;
}
wsa_sample_loop_add_to_cart_hook
Filter the hook, priority and function (`add_action` or `add_filter`)
that must be used to print the sample button in the shop/archive pages
add_filter( 'wsa_sample_loop_add_to_cart_hook', 'my_wsa_sample_loop_add_to_cart_hook' );
function my_wsa_sample_loop_add_to_cart_hook( $args ) {
// your code here...
return $args;
}
wsa_sample_maximum_quantity_description
Filter the description of the maximum quantity field
add_filter( 'wsa_sample_maximum_quantity_description', 'my_wsa_sample_maximum_quantity_description' );
function my_wsa_sample_maximum_quantity_description( $description ) {
// your code here...
return $description;
}
wsa_sample_quantity_setting_attributes
Filter the HTML attributes of the quantity setting field
add_filter( 'wsa_sample_quantity_setting_attributes', 'my_wsa_sample_quantity_setting_attributes' );
function my_wsa_sample_quantity_setting_attributes( $attributes ) {
// your code here...
return $attributes;
}
wsa_sample_should_add_button
Filter the condition determining whether a sample button should be displayed or not
add_filter( 'wsa_sample_should_add_button', 'my_wsa_sample_should_add_button', 10, 2 );
function my_wsa_sample_should_add_button( $is_button_visible, $sample ) {
// your code here...
return $is_button_visible;
}
wsa_sample_single_add_to_cart_attributes
Filter the attributes of the button element
add_filter( 'wsa_sample_single_add_to_cart_attributes', 'my_wsa_sample_single_add_to_cart_attributes', 10, 2 );
function my_wsa_sample_single_add_to_cart_attributes( $attributes, $sample ) {
// your code here...
return $attributes;
}
wsa_sample_single_add_to_cart_text
Filter the text used for the sample button on the single product pages. If you want to customize the button on the shop and archive pages, you have to use the wsa_sample_add_to_cart_text
filter hook instead.
add_filter( 'wsa_sample_single_add_to_cart_text', 'my_wsa_sample_single_add_to_cart_text', 10, 2 );
function my_wsa_sample_single_add_to_cart_text( $button_text, $sample ) {
if ( 0 === $sample->get_price() ) {
$button_text = __( 'Get a free sample!', 'my-text-domain' );
}
return $button_text;
}
wsa_sample_supports
Filter the file download path
add_filter( 'wsa_sample_supports', 'my_wsa_sample_supports', 10, 3 );
function my_wsa_sample_supports( $supported, $feature, $sample ) {
// your code here...
return $supported;
}
wsa_sample_update_sample_stock_query
Filter the SQL setting the stock quantity after the order
add_filter( 'wsa_sample_update_sample_stock_query', 'my_wsa_sample_update_sample_stock_query', 10, 4 );
function my_wsa_sample_update_sample_stock_query( $sql, $sample_id_with_stock, $new_stock, $operation ) {
// your code here...
return $sql;
}
Actions
wsa_sample_after_inventory_sample_data
add_action( 'wsa_sample_after_inventory_sample_data', 'my_wsa_sample_after_inventory_sample_data' );
function my_wsa_sample_after_inventory_sample_data() {
// your code here...
}
wsa_sample_after_loop_add_to_cart
add_action( 'wsa_sample_after_loop_add_to_cart', 'my_wsa_sample_after_loop_add_to_cart' );
function my_wsa_sample_after_loop_add_to_cart() {
// your code here...
}
wsa_sample_after_shipping_sample_data
add_action( 'wsa_sample_after_shipping_sample_data', 'my_wsa_sample_after_shipping_sample_data' );
function my_wsa_sample_after_shipping_sample_data() {
// your code here...
}
wsa_sample_before_general_sample_data
add_action( 'wsa_sample_before_general_sample_data', 'my_wsa_sample_before_general_sample_data' );
function my_wsa_sample_before_general_sample_data() {
// your code here...
}
wsa_sample_before_inventory_sample_data
add_action( 'wsa_sample_before_inventory_sample_data', 'my_wsa_sample_before_inventory_sample_data' );
function my_wsa_sample_before_inventory_sample_data() {
// your code here...
}
wsa_sample_before_loop_add_to_cart
add_action( 'wsa_sample_before_loop_add_to_cart', 'my_wsa_sample_before_loop_add_to_cart' );
function my_wsa_sample_before_loop_add_to_cart() {
// your code here...
}
wsa_sample_before_shipping_sample_data
add_action( 'wsa_sample_before_shipping_sample_data', 'my_wsa_sample_before_shipping_sample_data' );
function my_wsa_sample_before_shipping_sample_data() {
// your code here...
}
wsa_sample_cat_add_after_sample_price
add_action( 'wsa_sample_cat_add_after_sample_price', 'my_wsa_sample_cat_add_after_sample_price' );
function my_wsa_sample_cat_add_after_sample_price() {
// your code here...
}
wsa_sample_cat_edit_after_sample_price
add_action( 'wsa_sample_cat_edit_after_sample_price', 'my_wsa_sample_cat_edit_after_sample_price' );
function my_wsa_sample_cat_edit_after_sample_price() {
// your code here...
}
wsa_sample_delete_product_data
Fire right after product sample data has been deleted from the database
add_action( 'wsa_sample_delete_product_data', 'my_wsa_sample_delete_product_data' );
function my_wsa_sample_delete_product_data( $id ) {
// your code here...
}
wsa_sample_read_product_data
Fire right after product sample data has been read from the database
add_action( 'wsa_sample_read_product_data', 'my_wsa_sample_read_product_data' );
function my_wsa_sample_read_product_data( $id ) {
// your code here...
}
wsa_sample_updated_sample_stock
Fire an action for this direct update so it can be detected by other plugins.
add_action( 'wsa_sample_updated_sample_stock', 'my_wsa_sample_updated_sample_stock' );
function my_wsa_sample_updated_sample_stock( $sample_id_with_stock ) {
// your code here...
}