7Pillars.io, bLabs Ventures’ ‘Marketing On Demand’ shop, is built on a few platforms, WooCommerce being a major one for the foundation of our e-commerce needs.
The WooCommerce interface by default allows for a user to upload a series of images associated with each product. This works fine for selling clothing, candy, or other tangible goods – but in the case of our ‘Marketing On Demand’ services, we felt that a video explaining the service would be much more effective in place of a standard featured image.
There are several plug-ins that may be able to achieve some version of this – but I felt our need was too specific and thus, delved into a custom solution.
Below is a step-by-step solution of what I did to achieve the following acceptance criteria:
1. Create a field on a WooCommerce product page that accepts a video embed code.
2. If the field is NOT empty, display this video in place of featured image on the single-product page. If the field IS empty, show the featured image instead.
3. ONLY show this video on the single product page. Use the featured image on collection pages, cart pages, e-mails, and anywhere else it might appear.
With that in mind, let’s get started. To be clear, all code changes should be made within a child theme. If you aren’t already doing that, here’s the official WP documentation on Child Themes – https://developer.wordpress.org/themes/advanced-topics/child-themes/
Step 1 – Create a new ‘Product Video’ field in the WC product editor. Paste the following code at the bottom of your functions.php file
add_action( 'woocommerce_product_options_general_product_data', 'product_video_field' );
function product_video_field() {
$args = array(
'id' => 'product_video_field',
'label' => sanitize_text_field( 'Product Video' ),
'placeholder' => 'Cut and paste video embed code here',
'desc_tip' => true,
'style' => 'height:120px'
);
echo woocommerce_wp_textarea_input( $args );
}
add_action( 'woocommerce_process_product_meta', 'product_video_field_save' );
woocommerce_product_options_general_product_data hooks into the output of the ‘Product Data’ tab. There are more arguments available for woocommerce_wp_textarea_input, the above example only uses a few. See the function definition from WC docs for more info on that. The result is the following:
Now that we’ve created the field, we need to make sure the data is saved when we publish/update our product. To do this we hook into woocommerce_process_product_meta. Paste the below at the bottom your functions.php file.
add_action( 'woocommerce_process_product_meta', 'product_video_field_save' );
function product_video_field_save($post_id) {
$product_video_field = $_POST['product_video_field'];
update_post_meta($post_id, 'product_video_field', $product_video_field);
}
Step 2 – Output the video on the product page
To do this, we’ll need to modify the woocommerce single-product template file. To do this, create the following directories/file in your child theme: /your-child-theme/woocommerce/single-product/product-image.php
Cut and paste the below as the contents of the new product-image file.
<?php
/**
* Single Product Image
*
* This template can be overridden by copying it to yourtheme/woocommerce/single-product/product-image.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce/Templates
* @version 3.5.1
*/
defined( 'ABSPATH' ) || exit;
// Note: `wc_get_gallery_image_html` was added in WC 3.3.2 and did not exist prior. This check protects against theme overrides being used on older versions of WC.
if ( ! function_exists( 'wc_get_gallery_image_html' ) ) {
return;
}
global $product;
$columns = apply_filters( 'woocommerce_product_thumbnails_columns', 4 );
$post_thumbnail_id = $product->get_image_id();
$wrapper_classes = apply_filters( 'woocommerce_single_product_image_gallery_classes', array(
'woocommerce-product-gallery',
'woocommerce-product-gallery--' . ( $product->get_image_id() ? 'with-images' : 'without-images' ),
'woocommerce-product-gallery--columns-' . absint( $columns ),
'images',
) );
//for video, need to modify the wrapper classes, as they disable click events
$video_wrapper_classes = apply_filters( 'woocommerce_single_product_image_gallery_classes', array(
'woocommerce-product-gallery--' . ( $product->get_image_id() ? 'with-images' : 'without-images' ),
'woocommerce-product-gallery--columns-' . absint( $columns ),
'images',
) );
$product_video = get_post_meta(get_the_ID(), 'product_video_field', true );
$product_sub_image = get_the_post_thumbnail($post, [120]);
?>
<div class="<?php echo esc_attr( implode( ' ', array_map( 'sanitize_html_class', $video_wrapper_classes ) ) ); ?>" data-columns="<?php echo esc_attr( $columns ); ?>">
<figure class="woocommerce-product-gallery__wrapper">
<?php //if the product video field is not empty, output the video on the page.
if ( !empty($product_video)) { ?>
<div id="product-video-container">
<?php echo $product_video; ?>
</div>
<!--this is optional, display the featured image below the video, IF there is a video -->
<div id="product-sub-image-container">
<?php echo $product_sub_image; ?>
</div>
<?php } else {
//if no video, output featured image as per default template
if ( $product->get_image_id() ) {
$html = wc_get_gallery_image_html( $post_thumbnail_id, true );
} else {
$html = '<div class="woocommerce-product-gallery__image--placeholder">';
$html .= sprintf( '<img src="%s" alt="%s" class="wp-post-image" />', esc_url( wc_placeholder_img_src( 'woocommerce_single' ) ), esc_html__( 'Awaiting product image', 'woocommerce' ) );
$html .= '</div>';
}
}
echo apply_filters( 'woocommerce_single_product_image_thumbnail_html', $html, $post_thumbnail_id ); // phpcs:disable WordPress.XSS.EscapeOutput.OutputNotEscaped
do_action( 'woocommerce_product_thumbnails' );
?>
</figure>
</div>
As illustrated in the comment blocks, this template also contains an option to output the featured image underneath the video. If you don’t want that, simply erase these 3 lines:
<div id="product-sub-image-container">
<?php echo $product_sub_image; ?>
</div>
And with that, voila! An iframe/embed code taken from youtube, pasted into the field below, yields a responsive, featured video in place of our featured image.
That’s it! I would love to hear your questions, and also any modifications, customizations, and improvements you were able to attach to the above snippets.
Happy PHPing.
Dan Kurfirst,
Senior Developer