title: How to get all products in the cart in woocommerce?
body: <p>I am writing a custom shipping plugin for woocommerce based on <a href="https://docs.woocommerce.com/document/shipping-method-api/" rel="nofollow noreferrer">this article</a>, but the code I wrote only calculates shipping cost for one product, if I have several ones on the cart the shipping cost will be the same and won't change, for example if the shipping cost of one product is 14$ then if I keep adding more products to the cart the shipping cost will stay 14$.</p>
  <p>This is my plugin's code:</p>
  <pre><code>&lt;?php
   
  /**
   * Plugin Name: Namena Custom Shipping Method
   * Description: Custom Shipping Method for WooCommerce
   * Version: 1.0.0
   */
   
  if ( ! defined( 'WPINC' ) ) {
   
      die;
   
  }
   
  /*
   * Check if WooCommerce is active
   */
  if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
   
      function namena_custom_shipping_method() {
          if ( ! class_exists( 'Namena_Custom_shipping_Method' ) ) {
              class Namena_Custom_shipping_Method extends WC_Shipping_Method {
                  public function __construct() {
                      $this-&gt;id                 = 'namena-custom-shipping'; 
                      $this-&gt;method_title       = __( 'Namena Custom Shipping', 'namena-custom-shipping' );  
                      $this-&gt;method_description = __( 'Custom Shipping Method for Namena', 'namena-custom-shipping' ); 
                      $this-&gt;init();
   
                      $this-&gt;enabled = isset( $this-&gt;settings['enabled'] ) ? $this-&gt;settings['enabled'] : 'yes';
                      $this-&gt;title = isset( $this-&gt;settings['title'] ) ? $this-&gt;settings['title'] : __( 'Namena Custom Shipping', 'namena-custom-shipping' );
                  }
  
                  function init() {
                      $this-&gt;init_form_fields(); 
                      $this-&gt;init_settings(); 
                      add_action( 'woocommerce_update_options_shipping_' . $this-&gt;id, array( $this, 'process_admin_options' ) );
                  }
   
                  function init_form_fields() { 
   
                      $this-&gt;form_fields = array(
   
                       'enabled' =&gt; array(
                            'title' =&gt; __( 'Enable', 'namena-custom-shipping' ),
                            'type' =&gt; 'checkbox',
                            'description' =&gt; __( 'Enable this shipping.', 'namena-custom-shipping' ),
                            'default' =&gt; 'yes'
                            ),
   
                       'username' =&gt; array(
                          'title' =&gt; __( 'Username', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your Soluship username.', 'namena-custom-shipping' ),
                          'default' =&gt; __( '', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'password' =&gt; array(
                          'title' =&gt; __( 'Password', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your Soluship password.', 'namena-custom-shipping' ),
                          'default' =&gt; __( '', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'name' =&gt; array(
                          'title' =&gt; __( 'Name', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your name.', 'namena-custom-shipping' ),
                          'default' =&gt; __( 'Name', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'company' =&gt; array(
                          'title' =&gt; __( 'Company Name', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your company name.', 'namena-custom-shipping' ),
                          'default' =&gt; __( 'NAMENA Pharma Corp.', 'namena-custom-shipping' )
                          ),
                      'address' =&gt; array(
                          'title' =&gt; __( 'Address', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your address.', 'namena-custom-shipping' ),
                          'default' =&gt; __( 'Example address', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'postalCode' =&gt; array(
                          'title' =&gt; __( 'Postal Code', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your postal code.', 'namena-custom-shipping' ),
                          'default' =&gt; __( '', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'city' =&gt; array(
                          'title' =&gt; __( 'City', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your city.', 'namena-custom-shipping' ),
                          'default' =&gt; __( '', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'provinceCode' =&gt; array(
                          'title' =&gt; __( 'Province Code', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your province code.', 'namena-custom-shipping' ),
                          'default' =&gt; __( 'ON', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'phoneNumber' =&gt; array(
                          'title' =&gt; __( 'Phone Number', 'namena-custom-shipping' ),
                          'type' =&gt; 'number',
                          'description' =&gt; __( 'Your phone number.', 'namena-custom-shipping' ),
                          'default' =&gt; __( '1234567890', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      'email' =&gt; array(
                          'title' =&gt; __( 'Email', 'namena-custom-shipping' ),
                          'type' =&gt; 'text',
                          'description' =&gt; __( 'Your email.', 'namena-custom-shipping' ),
                          'default' =&gt; __( 'example@example.com', 'namena-custom-shipping' ),
                          'required'    =&gt; true,
                          ),
                      );
                      
                  }
  
                  public function calculate_shipping( $package = array()) {
                      $url = 'https://soluship.com/api/v1/';
                      $request_url = $url . 'login';
                      $username = $this-&gt;settings['username'];
                      $password = $this-&gt;settings['password'];
                      
                      $data = [
                          'userName' =&gt; $username,
                          'password' =&gt; $password
                      ];
                      
                      $curl = curl_init($request_url);
                      
                      // 1. Set the CURLOPT_RETURNTRANSFER option to true
                      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                      // 2. Set the CURLOPT_POST option to true for POST request
                      curl_setopt($curl, CURLOPT_POST, true);
                      // 3. Set the request data as JSON using json_encode function
                      curl_setopt($curl, CURLOPT_POSTFIELDS,  json_encode($data));
                      // 4. Set custom headers for RapidAPI Auth and Content-Type header
                      curl_setopt($curl, CURLOPT_HTTPHEADER, [
                        'Content-Type: application/json',
                        'LANGCODE: en_CA',
                        'COUNTRYCODE: CA'
                      ]);
                      
                      $response = curl_exec($curl);
                      
                      // Close cURL session
                      curl_close($curl);
                      
                      $data = json_decode($response);
                      
                      $token = $data-&gt;data-&gt;remembertoken;
                      
                      $request_url = $url . 'postalCode';
  
                      $postalCode = $package[ 'destination' ][ 'postcode' ];
  
                      $postalCode = str_replace(' ', '', $postalCode);
                      $data = [
                          'countryCode' =&gt; 'CA',
                          'postalCode' =&gt; $postalCode,
                      ];
  
                      $curl = curl_init($request_url);
  
                      // 1. Set the CURLOPT_RETURNTRANSFER option to true
                      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                      // 2. Set the CURLOPT_POST option to true for POST request
                      curl_setopt($curl, CURLOPT_POST, true);
                      // 3. Set the request data as JSON using json_encode function
                      curl_setopt($curl, CURLOPT_POSTFIELDS,  json_encode($data));
                      // 4. Set custom headers for RapidAPI Auth and Content-Type header
                      curl_setopt($curl, CURLOPT_HTTPHEADER, [
                      'Content-Type: application/json',
                      'LANGCODE: en_CA',
                      'COUNTRYCODE: CA'
                      ]);
  
                      $response = curl_exec($curl);
  
                      // Close cURL session
                      curl_close($curl);
  
                      $data = json_decode($response);
  
                      $address = $data-&gt;data;
  
  
  
                      $request_url = $url . 'getRates';
                          
                      date_default_timezone_set('Canada/Central');
  
                      $date = date('Y-m-d');
  
                      $data = '{
                          &quot;order&quot;:{
                              &quot;shipDate&quot;:&quot;' . $date .'&quot;,
                              &quot;dutiableAmount&quot;:&quot;0.00&quot;,
                              &quot;dutiableCurrency&quot;:&quot;CAD&quot;,
                              &quot;dangerousGoods&quot;:&quot;0&quot;,
                              &quot;packagetype&quot;:&quot;3&quot;,
                              &quot;signatureRequired&quot;:&quot;&quot;,
                              &quot;unitOfMeasureId&quot;:&quot;1&quot;,
                              &quot;additionalServiceData&quot;:&quot;&quot;,
                              &quot;mobileRatesType&quot;:&quot;mobileAPI&quot;
                          },
                          &quot;fromAddress&quot;:{
                              &quot;companyName&quot;:&quot;'. $this-&gt;settings['company'] .'&quot;,
                              &quot;address1&quot;:&quot;'. $this-&gt;settings['address'] .'&quot;,
                              &quot;address2&quot;:&quot;&quot;,
                              &quot;postalCode&quot;:&quot;'. $this-&gt;settings['postalCode'] .'&quot;,
                              &quot;countryCode&quot;:&quot;CA&quot;,
                              &quot;phone&quot;:&quot;'. $this-&gt;settings['phoneNumber'] .'&quot;,
                              &quot;attention&quot;:&quot;'. $this-&gt;settings['name'] .'&quot;,
                              &quot;emailAddress&quot;:&quot;'. $this-&gt;settings['email'] .'&quot;,
                              &quot;city&quot;:&quot;'. $this-&gt;settings['city'] .'&quot;,
                              &quot;provinceCode&quot;:&quot;'. $this-&gt;settings['provinceCode'] .'&quot;
                          },
                          &quot;toAddress&quot;:{
                              &quot;companyName&quot;:&quot;Company&quot;,
                              &quot;address1&quot;:&quot;'. $package[ 'destination' ][ 'address' ] .'&quot;,
                              &quot;address2&quot;:&quot;'. $package[ 'destination' ][ 'address_2' ] .'&quot;,
                              &quot;postalCode&quot;:&quot;'. $postalCode .'&quot;,
                              &quot;countryCode&quot;:&quot;'. $address-&gt;countryCode .'&quot;,
                              &quot;phone&quot;:&quot;9057619658&quot;,
                              &quot;attention&quot;:&quot;Example&quot;,
                              &quot;emailAddress&quot;:&quot;example@gmail.com&quot;,
                              &quot;city&quot;:&quot;'. $address-&gt;city .'&quot;,
                              &quot;provinceCode&quot;:&quot;'. $address-&gt;provinceCode .'&quot;
                          },
                          &quot;packages&quot;:[
                              {
                              &quot;length&quot;:&quot;4.00&quot;,
                              &quot;width&quot;:&quot;6.00&quot;,
                              &quot;height&quot;:&quot;4.00&quot;,
                              &quot;weight&quot;:&quot;1.5&quot;,
                              &quot;description&quot;:&quot;Ignite 6 boxes&quot;,
                              &quot;codValue&quot;:&quot;0.00&quot;,
                              &quot;insuranceAmount&quot;:&quot;0.00&quot;
                              }
                          ]
                      }';
                      
                      $request_url = $url . 'getRates';
                      
                      $curl = curl_init($request_url);
                      
                      // 1. Set the CURLOPT_RETURNTRANSFER option to true
                      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                      // 2. Set the CURLOPT_POST option to true for POST request
                      curl_setopt($curl, CURLOPT_POST, true);
                      // 3. Set the request data as JSON using json_encode function
                      curl_setopt($curl, CURLOPT_POSTFIELDS,  $data);
                      // 4. Set custom headers for RapidAPI Auth and Content-Type header
                      curl_setopt($curl, CURLOPT_HTTPHEADER, [
                        'Content-Type: application/json',
                        'LANGCODE: en_CA',
                        'COUNTRYCODE: CA',
                        'AUTHTOKEN: ' . $token
                      ]);
                      
                      $response = curl_exec($curl);
                      
                      // Close cURL session
                      curl_close($curl);
                      
                      
                      $decoded = json_decode($response);
                      $shippingMethods = $decoded-&gt;data;
                      
                      $i = 0;
                      foreach($shippingMethods as $key) {
                          if ($key-&gt;carrierName != 'Purolator') {
                              unset($shippingMethods[$i]);
                          }  
                          $i++; 
                      }
                      
                      $cheapest = reset($shippingMethods);
                      $cost = $cheapest-&gt;Total;
   
                      $rate = array(
                          'id' =&gt; $this-&gt;id,
                          'label' =&gt; $cheapest-&gt;carrierName . ' - ' . $cheapest-&gt;serviceName,
                          'cost' =&gt; $cost
                      );
   
                      $this-&gt;add_rate( $rate );
                      
                  }
              }
          }
      }
   
      add_action( 'woocommerce_shipping_init', 'namena_custom_shipping_method' );
   
      function add_namena_custom_shipping_method( $methods ) {
          $methods[] = 'Namena_Custom_shipping_Method';
          return $methods;
      }
   
      add_filter( 'woocommerce_shipping_methods', 'add_namena_custom_shipping_method' );
   
      function namena_validate_order( $posted )   {
   
          $packages = WC()-&gt;shipping-&gt;get_packages();
   
          $chosen_methods = WC()-&gt;session-&gt;get( 'chosen_shipping_methods' );
           
          if( is_array( $chosen_methods ) &amp;&amp; in_array( 'namena-custom-shipping', $chosen_methods ) ) {
               
              foreach ( $packages as $i =&gt; $package ) {
   
                  if ( $chosen_methods[ $i ] != &quot;namena-custom-shipping&quot; ) {
                               
                      continue;
                               
                  }
   
                  $Namena_Custom_Shipping_Method = new Namena_Custom_shipping_Method();
                  // $weightLimit = (int) $Namena_Custom_Shipping_Method-&gt;settings['weight'];
                  // $weight = 0;
   
                  // foreach ( $package['contents'] as $item_id =&gt; $values ) 
                  // { 
                  //     $_product = $values['data']; 
                  //     $weight = $weight + $_product-&gt;get_weight() * $values['quantity']; 
                  // }
   
                  // $weight = wc_get_weight( $weight, 'kg' );
                  
                  // if( $weight &gt; $weightLimit ) {
   
                  //         $message = sprintf( __( 'Sorry, %d kg exceeds the maximum weight of %d kg for %s', 'namena-custom-shipping' ), $weight, $weightLimit, $Namena_Custom_Shipping_Method-&gt;title );
                               
                  //         $messageType = &quot;error&quot;;
   
                  //         if( ! wc_has_notice( $message, $messageType ) ) {
                           
                  //             wc_add_notice( $message, $messageType );
                        
                  //         }
                  // }
              }       
          } 
      }
   
      add_action( 'woocommerce_review_order_before_cart_contents', 'namena_validate_order' , 10 );
      add_action( 'woocommerce_after_checkout_validation', 'namena_validate_order' , 10 );
  }
  </code></pre>
  <p>Let me explain how the API I am using to get the shipping cost works, basically you pass this data as a body of the POST request and then recieve the shipping cost:</p>
  <pre><code>                     $data = '{
                          &quot;order&quot;:{
                              &quot;shipDate&quot;:&quot;' . $date .'&quot;,
                              &quot;dutiableAmount&quot;:&quot;0.00&quot;,
                              &quot;dutiableCurrency&quot;:&quot;CAD&quot;,
                              &quot;dangerousGoods&quot;:&quot;0&quot;,
                              &quot;packagetype&quot;:&quot;3&quot;,
                              &quot;signatureRequired&quot;:&quot;&quot;,
                              &quot;unitOfMeasureId&quot;:&quot;1&quot;,
                              &quot;additionalServiceData&quot;:&quot;&quot;,
                              &quot;mobileRatesType&quot;:&quot;mobileAPI&quot;
                          },
                          &quot;fromAddress&quot;:{
                              &quot;companyName&quot;:&quot;'. $this-&gt;settings['company'] .'&quot;,
                              &quot;address1&quot;:&quot;'. $this-&gt;settings['address'] .'&quot;,
                              &quot;address2&quot;:&quot;&quot;,
                              &quot;postalCode&quot;:&quot;'. $this-&gt;settings['postalCode'] .'&quot;,
                              &quot;countryCode&quot;:&quot;CA&quot;,
                              &quot;phone&quot;:&quot;'. $this-&gt;settings['phoneNumber'] .'&quot;,
                              &quot;attention&quot;:&quot;'. $this-&gt;settings['name'] .'&quot;,
                              &quot;emailAddress&quot;:&quot;'. $this-&gt;settings['email'] .'&quot;,
                              &quot;city&quot;:&quot;'. $this-&gt;settings['city'] .'&quot;,
                              &quot;provinceCode&quot;:&quot;'. $this-&gt;settings['provinceCode'] .'&quot;
                          },
                          &quot;toAddress&quot;:{
                              &quot;companyName&quot;:&quot;Company&quot;,
                              &quot;address1&quot;:&quot;'. $package[ 'destination' ][ 'address' ] .'&quot;,
                              &quot;address2&quot;:&quot;'. $package[ 'destination' ][ 'address_2' ] .'&quot;,
                              &quot;postalCode&quot;:&quot;'. $postalCode .'&quot;,
                              &quot;countryCode&quot;:&quot;'. $address-&gt;countryCode .'&quot;,
                              &quot;phone&quot;:&quot;9057619658&quot;,
                              &quot;attention&quot;:&quot;Example&quot;,
                              &quot;emailAddress&quot;:&quot;example@gmail.com&quot;,
                              &quot;city&quot;:&quot;'. $address-&gt;city .'&quot;,
                              &quot;provinceCode&quot;:&quot;'. $address-&gt;provinceCode .'&quot;
                          },
                          &quot;packages&quot;:[
                              {
                              &quot;length&quot;:&quot;4.00&quot;,
                              &quot;width&quot;:&quot;6.00&quot;,
                              &quot;height&quot;:&quot;4.00&quot;,
                              &quot;weight&quot;:&quot;1.5&quot;,
                              &quot;description&quot;:&quot;Example&quot;,
                              &quot;codValue&quot;:&quot;0.00&quot;,
                              &quot;insuranceAmount&quot;:&quot;0.00&quot;
                              }
                          ]
                      }';
  </code></pre>
  <p>The array at the end (packages) is what I need to add more elements to so I can get the shipping cost for several packages, so my question is how to get the total number of items in the cart each time it gets updated and then execute calculate_shipping function? also if you have a better suggestion on how to do this please let me know.</p>
  <p>If anything is unclear please do ask me I will do my best to explain, I don't post much questions here.</p>
  <p>Edit 1:
  I tried using <code>WC()-&gt;shipping-&gt;get_packages();</code> so I can get number of packages but it didn't work.</p>
  <p>Edit 2:
  For now I used <code>WC()-&gt;cart-&gt;get_cart_contents_count();</code> to get the cart count so I can at least add all indentical packages as a workaround.</p>