├── README.md └── woocommerce-subscriptions-manual-repair.php /README.md: -------------------------------------------------------------------------------- 1 | > IMPORTANT: This code is made available in the hope that it will be useful, but **without any warranty**. See the GNU General Public License included with the code for more details. Automattic or WooCommerce support services are also not available to assist with the use of this code. 2 | 3 | ## WooCommerce Subscriptions Recalculate Subscription Totals 4 | 5 | In some cases, if the tax settings change after some subscriptions have been created, their totals need to be recalculated in order to include the proper taxes. This plugin recalculates all the subscriptions totals. 6 | 7 | To run the plugin, add `?wcs-recalculate-totals=true` to any admin URL. 8 | - Add `&readd` parameter (`?wcs-recalculate-totals=true&readd=true`) to force the plugin to delete all line items of the order and add them again before recalculating the totals (this helps in case tax settings have changed and the tax it not included properly just by recalculating the order totals) 9 | 10 | For each iteration of the fixer's code, a log entry will be added to a log file prefixed with `'wcs-recalculate-totals'`. To view this log file, visit **WooCommerce > System Status > Logs**. 11 | 12 | ### Important 13 | 14 | This is an experimental extension and it hasn't been tested in all scenarios. Please **backup your database before running it** and **try it first on a staging/development version of your site** (confirm that all the products have been added again with the correct prices, taxes, shipping, etc) before running it on a production site. 15 | 16 | ### How to update the same subscriptions again? 17 | All the subscripitons that have been already updated by the plugin will not be processed a second time because their ID is stored in the `wcs_subscriptions_with_totals_updated` option. If you want to reset it to be able to process all your subscriptions again, you'll need to add the `?reset-updated-subs-option=true` parameter to the URL. 18 | 19 | ### Installation 20 | 21 | 1. Upload the plugin's files to the `/wp-content/plugins/` directory of your WordPress site 22 | 1. Activate the plugin through the **Plugins** menu in WordPress 23 | 24 | 25 | #### License 26 | 27 | This plugin is released under [GNU General Public License v3.0](http://www.gnu.org/licenses/gpl-3.0.html). 28 | 29 | --- 30 | 31 |

32 | 33 |

34 | -------------------------------------------------------------------------------- /woocommerce-subscriptions-manual-repair.php: -------------------------------------------------------------------------------- 1 | . 27 | * 28 | * @package WooCommerce Subscriptions 29 | * @author Prospress Inc. 30 | * @since 1.0 31 | */ 32 | 33 | function wcs_recalculate_totals() { 34 | 35 | // If requested, backup and reset the "wcs_subscriptions_with_totals_updated" option 36 | if ( isset( $_GET['reset-updated-subs-option'] ) ) { 37 | $old_option = get_option( 'wcs_subscriptions_with_totals_updated', array() ); 38 | update_option( '_old_wcs_subscriptions_with_totals_updated', $old_option, false ); 39 | update_option( 'wcs_subscriptions_with_totals_updated', '', false ); 40 | return; 41 | } 42 | 43 | // Use a URL param to act as a flag for when to run the fixes - avoids running fixes in multiple requests at the same time 44 | if ( ! isset( $_GET['wcs-recalculate-totals'] ) ) { 45 | return; 46 | } 47 | 48 | $payment_gateways = WC()->payment_gateways->payment_gateways(); 49 | $checked_subscriptions = get_option( 'wcs_subscriptions_with_totals_updated', array() ); 50 | $subscriptions_to_check = get_posts( array( 51 | 'fields' => 'ids', 52 | 'orderby' => 'ID', 53 | 'order' => 'DESC', 54 | 'post_type' => 'shop_subscription', 55 | 'posts_per_page' => 50, 56 | 'post__not_in' => $checked_subscriptions, 57 | 'post_status' => array( 58 | 'wc-active', 59 | 'wc-on-hold', 60 | ), 61 | ) ); 62 | 63 | $logger = new WC_Logger(); 64 | $logger->add( 'wcs-recalculate-totals', '----------- Initiating Recalculate subscription totals Fixer -----------' ); 65 | $logger->add( 'wcs-recalculate-totals', 'Checked subscriptions = ' . var_export( $checked_subscriptions, true ) ); 66 | $logger->add( 'wcs-recalculate-totals', 'Subscriptions to check = ' . var_export( $subscriptions_to_check, true ) ); 67 | 68 | foreach ( $subscriptions_to_check as $subscription_id ) { 69 | 70 | $logger->add( 'wcs-recalculate-totals', '------ Checking subscription with ID = ' . var_export( $subscription_id, true ) ); 71 | 72 | $subscription = wcs_get_subscription( $subscription_id ); 73 | $order = wc_get_order( $subscription_id ); 74 | $order_data = $order->get_data(); 75 | $products_data = array(); 76 | 77 | if ( $subscription ) { 78 | 79 | $calc_total = $subscription->calculate_totals(); 80 | 81 | if(isset($_GET['readd'])){ 82 | // Backup line items (product_id => quantity) 83 | foreach ( $subscription->get_items() as $item_id => $item ) { 84 | $qtty = $item['quantity']; 85 | $product_id = $item['product_id']; 86 | if(isset($item['variation_id']) && $item['variation_id']!=''){ 87 | $product_id = $item['variation_id']; 88 | } 89 | $products_data[$product_id] = $qtty; 90 | } 91 | $logger->add( 'wcs-recalculate-totals', '* Saved line items ' . var_export( $products_data, true ) ); 92 | 93 | // Delete all order items 94 | $subscription->remove_order_items('line_item'); 95 | $logger->add( 'wcs-recalculate-totals', '* Removed order items' ); 96 | 97 | // Add the saved order items 98 | foreach($products_data as $product_id => $qty) { 99 | if($qty > 0) { 100 | $product = wc_get_product($product_id); 101 | $subscription->add_product($product, $qty); 102 | $logger->add( 'wcs-recalculate-totals', "* Added $qty units of product #$product_id" ); 103 | } 104 | } 105 | 106 | // Update totals and add an order note 107 | $subscription->update_taxes(); 108 | $calc_total = $subscription->calculate_totals(); 109 | $subscription->save(); 110 | $order->add_order_note("Order totals recalculated automatically (woocommerce-subscriptions-recalculate-totals)"); 111 | $logger->add( 'wcs-recalculate-totals', "* Recalculated totals" ); 112 | 113 | } 114 | 115 | } 116 | 117 | $checked_subscriptions[] = $subscription_id; 118 | 119 | // Update the record on each iteration in case we can't make it through 50 subscriptions in one request 120 | update_option( 'wcs_subscriptions_with_totals_updated', $checked_subscriptions, false ); 121 | } 122 | } 123 | add_action( 'init', 'wcs_recalculate_totals' ); 124 | 125 | function general_admin_notice(){ 126 | 127 | if ( ! isset( $_GET['wcs-recalculate-totals'] ) ) { 128 | return; 129 | } 130 | 131 | $checked_subscriptions = get_option( 'wcs_subscriptions_with_totals_updated', array() ); 132 | $subscriptions_to_check = get_posts( array( 133 | 'fields' => 'ids', 134 | 'orderby' => 'ID', 135 | 'order' => 'DESC', 136 | 'post_type' => 'shop_subscription', 137 | 'posts_per_page' => 50, 138 | 'post__not_in' => $checked_subscriptions, 139 | 'post_status' => array( 140 | 'wc-active', 141 | 'wc-on-hold', 142 | ), 143 | ) ); 144 | 145 | if ( $checked_subscriptions!='' && empty($subscriptions_to_check) ) { 146 | echo '
147 |

All subscriptions have been recalculated! :)

148 |

If you want to recalculate all your subscriptions again, you will need to use "reset-updated-subs-option=true" parameter

149 |
'; 150 | } 151 | 152 | $logger = new WC_Logger(); 153 | $logger->add( 'wcs-recalculate-totals', '******** All subscriptions have been recalculated! ********' ); 154 | 155 | } 156 | add_action('admin_notices', 'general_admin_notice'); 157 | --------------------------------------------------------------------------------