Q:

Check if a product variation is in cart in Woocommerce

I am trying display if a variation of a product is already in a cart or not (in single product page). A simple comparing of the product id with products in cart object is not working for variable product as the variation id is being loaded using ajax.  
Here is my code that works in case the product type is other than variable.  
<?php
/*
 * Check if Product Already In Cart
*/
function woo_in_cart( $product_id ) {
    global $woocommerce;

    if ( !isset($product_id) ) {
        return false;
    }

    foreach( $woocommerce->cart->get_cart() as $cart_item ) {
        if ( $cart_item['product_id'] === $product_id ){
            return true;
        } else {
            return false;
        }
    }
}  

Is there any way to make it work without jQuery?

A:

Do you mean $product_id could be the ID of a variation? If so, you can just get the parent ID if it exists:
/*
 * Check if Product Already In Cart
 */
function woo_in_cart( $product_id ) {
    global $woocommerce;

    if ( ! isset( $product_id ) ) {
        return false;
    }

    $parent_id  = wp_get_post_parent_id( $product_id );
    $product_id = $parent_id > 0 ? $parent_id : $product_id;

    foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
        if ( $cart_item['product_id'] === $product_id ) {
            return true;
        } else {
            return false;
        }
    }
}

If you mean your cart item is a variation, and $product_id is already the parent product ID, then your code should work already as is.
The $cart_item has 2 IDs: $cart_item['product_id'] and $cart_item['variation_id'].
So product_id will always be that of the parent product.

A:

To handle product variations outside single product pages (and simple products everywhere):
// Check if Product Already In Cart (Work with product variations too)
function woo_in_cart( $product_id = 0 ) {
    $found = false;
    if ( isset($product_id) || 0 == $product_id )
        return $found;

    foreach( WC()->cart->get_cart() as $cart_item ) {
        if ( $cart_item['data']->get_id() == $product_id )
            $found = true;
    }
    return $found;
}

To handle product variations inside single product pages, javascript is needed. 
Here is an example that will show a custom message, when the selected variation is already in cart:
// Frontend: custom select field in variable products single pages
add_action( 'wp_footer', 'action_before_add_to_cart_button' );
function action_before_add_to_cart_button() {
    if( ! is_product() ) return;

    global $product;

    if( ! is_object($product) )
        $product = wc_get_product( get_the_id() );

    // Only for variable products when cart is not empty
    if( ! ( $product->is_type('variable') && ! WC()->cart->is_empty() ) ) return; // Exit

    $variation_ids_in_cart = array();

    // Loop through cart items
    foreach( WC()->cart->get_cart() as $cart_item ) {
        // Collecting product variation IDs if they are in cart for this variable product
        if ( $cart_item['variation_id'] > 0 && in_array( $cart_item['variation_id'], $product->get_children() ) )
            $variation_ids_in_cart[] = $cart_item['variation_id'];
    }

    // Only if a variation ID for this variable product is in cart
    if( sizeof($variation_ids_in_cart) == 0 ) return; // Exit

    // Message to be displayed (if the selected variation match with a variation in cart
    $message = __("my custom message goes here", "woocommerce");
    $message = '<p class="custom woocommerce-message" style="display:none;">'.$message.'</p>';

    // jQuery code
    ?>
    <script>
    (function($){
        // Utility function that check if variation match and display message
        function checkVariations(){
            var a = 'p.woocommerce-message.custom', b = false;
            $.each( <?php echo json_encode($variation_ids_in_cart); ?>, function( k, v ){
                if( $('input[name="variation_id"]').val() == v ) b = true;
            });
            if(b) $(a).show(); else $(a).hide();
        }

        // On load (when DOM is rendered)
        $('table.variations').after('<?php echo $message; ?>');
        setTimeout(function(){
            checkVariations();
        }, 800);

        // On live event: product attribute select fields "blur" event
        $('.variations select').blur( function(){
            checkVariations();
        });
    })(jQuery);
    </script>
    <?php
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

