Does add_filter work outside functions.php

The functions for filter and action manipulation are available at any point after WordPress loads wp-includes/plugin.php – this happens quite early as much of WordPress itself depends on these functions, so they are always accessible to theme and plugin files alike.

You need to add header information to your file such that WordPress may recognize it as a plugin, then activate the plugin in your installation’s administrative dashboard.

/*
Plugin Name: My Plugin
Description: Disable free shipping for select products
Author:      Keryn Gill
*/

/**
 * Disable free shipping for select products
 *
 * @param bool $is_available
 */
function my_free_shipping( $is_available ) {
    global $woocommerce;
    $ineligible = array( '4616', '14031' );
    $cart_items = $woocommerce->cart->get_cart();

    foreach ( $cart_items as $key => $item ) {
        if( in_array( $item['product_id'], $ineligible ) ) {
            return false;
        }
    }
    return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'my_free_shipping', 20 );

Alternately, place your plugin file directly in wp-content/mu-plugins to have WordPress interpret it as a must-use plugin – this will remove your plugin from the dashboard list and treat it as though it is always active. This practice is best reserved for your own code, as third-party plugins placed in this directory will not trigger activation/deactivation hooks nor will they receive automatic updates.