During a recent customer support interaction for one of our WooCommerce plugins, we encountered a situation where the customer’s currently active WordPress child theme contained outdated template files, including some from our own plugins. This issue came to light while assisting the customer in debugging a separate issue.
This experience prompted us, as WooCommerce developers, to reevaluate how we handle template files and overrides. We wanted to provide shop owners with a clear notice when our template files were updated, especially when their active theme contained outdated overrides.
Upon examination, we found that WooCommerce already had a robust mechanism in place for this purpose. Their code included functionalities such as:
Adding a custom notice in the admin to alert shop owners about outdated template overrides.
Removing a notice once the template overrides were updated.
Checking if a notice was already present.
Scanning for template files in a given directory.
Returning the WooCommerce template path, allowing checks in both the core theme directory and WooCommerce template directory when looking for outdated templates.
Getting the template file version for comparison to identify outdated versions.
Although there wasn’t a direct hook for us to use within WooCommerce, we decided to port the relevant code into our own plugin. This allowed us to reuse the functionality mentioned above, performing the necessary checks and generating the desired output.
Below is an example of the code we implemented:
/**
* Template version check
*
* @since 2.4.0
* @param bool $skip_notice_check "true" will run the check regardless of a missing persisting notice
* @return void
*/
public function template_version_check( $skip_notice_check = false ) {
if ( ( ! WC_Admin_Notices::has_notice( 'wcwl_outdated_templates' ) && $skip_notice_check ) ||
WC_Admin_Notices::has_notice( 'wcwl_outdated_templates' ) ) {
$plugin_dir = dirname(__FILE__);
if ( !is_dir( $plugin_dir ) ) {
return;
}
$core_templates = WC_Admin_Status::scan_template_files( $plugin_dir . '/templates' );
$outdated = false;
foreach ( $core_templates as $file ) {
$theme_file = false;
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
} elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
} elseif ( file_exists(get_template_directory() . '/' . WC()->template_path() . $file ) ) {
$theme_file = get_template_directory() . '/' . WC()->template_path() . $file;
}
if ( false !== $theme_file ) {
$core_version = WC_Admin_Status::get_file_version( $plugin_dir . '/templates/' . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && $theme_version && version_compare( $theme_version, $core_version, '<' ) ) {
$outdated = true;
break;
}
}
}
if ( $outdated ) {
if ( ! WC_Admin_Notices::has_notice( 'wcwl_outdated_templates' ) ) {
WC_Admin_Notices::add_custom_notice( 'wcwl_outdated_templates', $this->template_version_html() );
}
} else {
WC_Admin_Notices::remove_notice( 'wcwl_outdated_templates' );
}
}
}
Breaking down the function:
The first IF
statement establishes conditions for when to run the checks, allowing us to add or remove the notice as needed. We proceed when either the notice is not present and we’ve flagged the function to check for it or when the notice is already present. This flexibility enables us to trigger the function when a user switches themes (using the switch_theme
hook) or when our plugin is updated (handled through version check functionality).
After a sanity check on the current directory, we collect all template files from our plugin and set a flag ($outdated = false
) to update if any outdated files are found in the theme. We use WooCommerce’s scan_template_files
function to retrieve the plugin templates, returning an array of filenames for the given path, including subdirectories.
We loop through these core templates, setting the $template_file
flag to false initially, indicating that a file has not been found. Within this loop, we check four locations for a template override: the root directory and WooCommerce template path of both the child and parent themes.
If a template override is found, the loop retrieves the version of the template for both the override found in the theme and the version in our plugin. If the version of the override is less than that of the core plugin template, $outdated
is set to true, and the loop exits. Otherwise, the loop continues until all files have been checked.
Upon finding an outdated plugin, we perform a check to ensure a notice is not already in place. If not, we add our custom notice to alert the shop owner. The template_version_html()
function returns the HTML from a custom template file we use to store the notice.
If no outdated override is found, we remove the notice if it exists.
By leveraging WooCommerce functionality in this way, we can provide a user experience similar to the one they might have encountered with WooCommerce notices. This familiarity is likely to be beneficial to users who have previously seen such notices from WooCommerce while using custom templates in their themes.
In the future, our plan is to integrate into the WooCommerce status page to provide information about our plugin, including details about any template overrides in use and their update status in the currently active theme.