title: Show cross-sells before same category on related products in WooCommerce
body: <p>I'm writing some code to modify the related products section as follows:</p>
  
  <ul>
  <li>If a product has cross sell products, show those first, and fill up to 4 total products with others from the same category*</li>
  </ul>
  
  <p>Or</p>
  
  <ul>
  <li>If a product has no cross sell products, show 4 products from the same category*</li>
  </ul>
  
  <p>Here's my function to filter the related products so far:</p>
  
  <pre class="lang-php prettyprint-override"><code>add_filter( 'woocommerce_related_products', 'fivem_add_linked_to_related_products', 9999, 3 );
  function fivem_add_linked_to_related_products( $related_posts, $product_id, $args ) {
  
      $product = wc_get_product( $product_id );
      $cross_sell_ids = $product-&gt;get_cross_sell_ids();
      $product_categories = $product-&gt;get_category_ids();
  
      // Get cross sell products
      $cross_sell_products = get_posts( array(
          'post_type' =&gt; 'product',
          'post_status' =&gt; 'publish',
          'fields' =&gt; 'ids',
          'post__in' =&gt; $cross_sell_ids,
          'posts_per_page' =&gt; 4,
          'exclude' =&gt; array( $product_id ),
      ));
  
      // Calculate how many filler products are needed
      $category_product_count = 4 - count( $cross_sell_products );
  
      // Exclude main product and cross sell products
      $excluded_products = array_push( $cross_sell_ids, $product_id );
  
      // Get filler products from same category
      $category_products = get_posts( array(
          'post_type' =&gt; 'product',
          'post_status' =&gt; 'publish',
          'orderby' =&gt; 'rand',
          'fields' =&gt; 'ids',
          'post__not_in' =&gt; $excluded_products,
          'posts_per_page' =&gt; $category_product_count,
          'tax_query' =&gt; array(
              array(
                  'taxonomy' =&gt; 'product_cat',
                  'field' =&gt; 'id',
                  'terms' =&gt; $product_categories,
                  'operator' =&gt; 'IN',
              )
          )
      ));
  
      // Merge cross sell products with filler products
      $related_products = array_merge( $cross_sell_products, $category_products );
  
      // Return related products
      return $related_products;
  
  }
  </code></pre>
  
  <hr>
  
  <p>Currently, the above code mostly works.</p>
  
  <ul>
  <li>If cross-sells are set, it only displays those cross-sell products- ie. does not fill out to 4 total</li>
  <li>If no cross-sells are set, it displays products from the same category as expected.</li>
  </ul>
  
  <p>There are two problems I'm trying to solve:</p>
  
  <ol>
  <li>Code above doesn't fill with category products. If I remove the <em>post__not_in</em> and <em>tax_query</em> arguments, it fills out, but obviously not with products from the same category.</li>
  <li>I want to show cross-sell products first, then the category-related products. There appears to be another randomization somewhere that mixes the order up, and I can't work out where that comes from.</li>
  </ol>
  
  <p>Any ideas how I can fix this? Thanks in advance.</p>