2
\$\begingroup\$

I am trying to create a custom WordPress/WooCommerce function in PHP. I am a newbie and would really appreciate some feedback on my code and how to improve the code! Right now it feels like there is a lot of duplication where there probably is a smarter and better way to do it.

Overall the function is used to hide shipping methods. Besides the usual shipping methods then some items is shipped in pallets by either quarter, half or full. When an item with shipping class of full pallet is in the cart, for example, it should hide all other shipping methods and so on.

// SHIPPING METHOD BASED ON SHIPPINGCLASS - FULL PALLET
add_filter('woocommerce_package_rates', 'wtf_hide_shipping_method_based_on_shipping_class', 10, 2);

function wtf_hide_shipping_method_based_on_shipping_class($available_shipping_methods, $package)
{
    $hide_when_shipping_class_exist = array(
        171 => array(
            'pakkelabels_shipping_gls_private',
            'pakkelabels_shipping_postnord_private',
            'pakkelabels_shipping_gls',
            'pakkelabels_shipping_pdk',
            'flat_rate:15',
            'flat_rate:14'
        )
    );

    $hide_when_shipping_class_not_exist = array(
        171 => array(
            'flat_rate:12'
        )
    );


    $shipping_class_in_cart = array();
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
       $shipping_class_in_cart[] = $values['data']->get_shipping_class_id();
    }

    foreach($hide_when_shipping_class_exist as $class_id => $methods) {
        if(in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    foreach($hide_when_shipping_class_not_exist as $class_id => $methods) {
        if(!in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    return $available_shipping_methods;
}

// SHIPPING METHOD BASED ON SHIPPINGCLASS - HALF PALLET
add_filter('woocommerce_package_rates', 'wfe_hide_shipping_method_based_on_shipping_class', 10, 2);

function wfe_hide_shipping_method_based_on_shipping_class($available_shipping_methods, $package)
{
    $hide_when_shipping_class_exist = array(
        169 => array(
            'pakkelabels_shipping_gls_private',
            'pakkelabels_shipping_postnord_private',
            'pakkelabels_shipping_gls',
            'pakkelabels_shipping_pdk',
            'flat_rate:15'
        )
    );

    $hide_when_shipping_class_not_exist = array(
        169 => array(
            'flat_rate:14'
        )
    );


    $shipping_class_in_cart = array();
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
       $shipping_class_in_cart[] = $values['data']->get_shipping_class_id();
    }

    foreach($hide_when_shipping_class_exist as $class_id => $methods) {
        if(in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    foreach($hide_when_shipping_class_not_exist as $class_id => $methods) {
        if(!in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    return $available_shipping_methods;
}

// SHIPPING METHOD BASED ON SHIPPINGCLASS - QUARTER PALLET
add_filter('woocommerce_package_rates', 'wf_hide_shipping_method_based_on_shipping_class', 10, 2);

function wf_hide_shipping_method_based_on_shipping_class($available_shipping_methods, $package)
{
    $hide_when_shipping_class_exist = array(
        211 => array(
            'pakkelabels_shipping_gls_private',
            'pakkelabels_shipping_postnord_private',
            'pakkelabels_shipping_gls',
            'pakkelabels_shipping_pdk',
        )
    );

    $hide_when_shipping_class_not_exist = array(
        211 => array(
            'flat_rate:15'
        )
    );


    $shipping_class_in_cart = array();
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
       $shipping_class_in_cart[] = $values['data']->get_shipping_class_id();
    }

    foreach($hide_when_shipping_class_exist as $class_id => $methods) {
        if(in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    foreach($hide_when_shipping_class_not_exist as $class_id => $methods) {
        if(!in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    return $available_shipping_methods;
}
\$\endgroup\$
1
\$\begingroup\$

I recommend establishing a single "lookup" array that groups your three filtering arrays and assigns new, meaningful grouping keys. Something like this:

$method_filters = [
    'exists' => [
        'full pallet' => [
            171 => [
                    'pakkelabels_shipping_gls_private',
                    'pakkelabels_shipping_postnord_private',
                    'pakkelabels_shipping_gls',
                    'pakkelabels_shipping_pdk',
                    'flat_rate:15',
                    'flat_rate:14'
                   ],
        ],
        'half pallet' => [
            169 => [
                    'pakkelabels_shipping_gls_private',
                    'pakkelabels_shipping_postnord_private',
                    'pakkelabels_shipping_gls',
                    'pakkelabels_shipping_pdk',
                    'flat_rate:15'
                   ],
        ],
        'quarter pallet' => [
            211 => [
                    'pakkelabels_shipping_gls_private',
                    'pakkelabels_shipping_postnord_private',
                    'pakkelabels_shipping_gls',
                    'pakkelabels_shipping_pdk'
                   ],
        ]
    ],
    'not exists' => [
        'full pallet' => [
            171 => [
                    'flat_rate:12'
                   ]
        ],
        'half pallet' => [
            169 => [
                    'flat_rate:14'
                   ]
        ],
        'quarter pallet' => [
            211 => [
                    'flat_rate:15'
                   ]
        ]
    ]
];

In php7+, you can even define() the array as a constant since your design will never need to mutate the initial values. Constants have the added benefit of being accessible in any scope so you won't need to pass the array into your function.

Now that your data is all in one place, you can write a single function with parameters to drill down to the appropriate subarray or you can use foreach loops to traverse all of the subarrays.

When you are isolating your cart ids with foreach(WC()->cart->get_cart_contents() as $key => $values) {...

  1. You don't use $key so that declaration can be omitted.
  2. You can enjoy the ease of comparison in your next step by storing the ids as keys in your temporary array.

Something like this:

foreach(WC()->cart->get_cart_contents() as $item) {
    $class_ids[$item['data']->get_shipping_class_id()] = '';
}

Now there are a few different ways to design the iterative unset() task.

foreach ($method_filters as $filter_type => $pallet_filters) {               // iterate exists/not exists level
    foreach ($pallet_filters as $pallet_type => $shipping_methods) {         // iterate different pallets level
        if ($filter_type == 'exists') {
            $qualifiers = array_intersect_key($shipping_methods, $class_ids);
        } else {
            $qualifiers = array_diff_key($shipping_methods, $class_ids);
        }
        foreach ($qualifiers as $class_id => $method_names) {  // only iterate if there are qualifying class ids
            foreach ($method_names as $method_name) {
                unset($available_shipping_methods[$method_name]);
            }
        }
    }
}

Granted there will be a number of ways to set up the lookup array and a number of ways of iterating the lookup array data. I have performed a basic check that my suggestions work - and I think it works as desired - but you should definitely test it on your project data to be absolutely sure. https://3v4l.org/r4WPg or with a CONSTANT: https://3v4l.org/uqcte

With such a busy block of language constructs, it is imperative that you practice sensible variable naming so that no one gets blurry-eyed reviewing your script (not that you had that issue in your posted code).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.