Here’s my solution to this. In my situation, the “Related Products” section didn’t make sense (as the store was already organized based on categories), so I removed the standard related products section and re-added it with the same template, but by feeding the template the cross-sells instead of the related products. The section still says “Related Products” and will look the same, but is populated with cross-sell products instead.
// Remove "related Products"
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
// Show cross-sells using related template on single product page
// see https://docs.woocommerce.com/wc-apidocs/source-function-woocommerce_related_products.html#1264-1296
function wc_output_cross_sells() {
$crosssells = get_post_meta( get_the_ID(), '_crosssell_ids', true );
$args = array(
'posts_per_page' => 2,
'columns' => 2,
'orderby' => 'rand',
'order' => 'desc',
);
$args['related_products'] = array_map( 'wc_get_product', $crosssells );
// Set global loop values.
$woocommerce_loop['name'] = 'related';
$woocommerce_loop['columns'] = apply_filters( 'woocommerce_related_products_columns', $args['columns'] );
wc_get_template( 'single-product/related.php', $args );
}
add_action('woocommerce_after_single_product_summary', 'wc_output_cross_sells', 30);